如何获得毫秒分辨率的 Windows 系统时间?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3729169/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I get the Windows system time with millisecond resolution?
提问by axilmar
How can I get the Windows system time with millisecond resolution?
如何获得毫秒分辨率的 Windows 系统时间?
If the above is not possible, then how can I get the operating system start time? I would like to use this value together with timeGetTime() in order to compute a system time with millisecond resolution.
如果以上都不可能,那么我如何获得操作系统的启动时间?我想将此值与 timeGetTime() 一起使用,以便以毫秒分辨率计算系统时间。
Thank you in advance.
先感谢您。
采纳答案by Joel Clark
GetTickCount
will not get it done for you.
GetTickCount
不会为你完成。
Look into QueryPerformanceFrequency
/ QueryPerformanceCounter
. The only gotcha here is CPU scaling though, so do your research.
查看QueryPerformanceFrequency
/ QueryPerformanceCounter
。不过,这里唯一的问题是 CPU 扩展,因此请进行研究。
回答by Kevin Gale
Try this article from MSDN Magazine. It's actually quite complicated.
试试 MSDN 杂志上的这篇文章。它实际上相当复杂。
Implement a Continuously Updating, High-Resolution Time Provider for Windows
回答by Brian
This is an elaboration of the above comments to explain the some of the whys.
这是对上述评论的详细说明,以解释其中的一些原因。
First, the GetSystemTime* calls are the only Win32 APIs providing the system's time. This time has a fairly coarse granularity, as most applications do not need the overhead required to maintain a higher resolution. Time is (likely) stored internally as a 64-bit count of milliseconds. Calling timeGetTime gets the low order 32 bits. Calling GetSystemTime, etc requests Windows to return this millisecond time, after converting into days, etc and including the system start time.
首先,GetSystemTime* 调用是唯一提供系统时间的 Win32 API。这个时间的粒度相当粗,因为大多数应用程序不需要维持更高分辨率所需的开销。时间(可能)在内部存储为 64 位毫秒计数。调用 timeGetTime 获取低 32 位。调用 GetSystemTime 等请求 Windows 在转换为天等并包括系统启动时间后返回此毫秒时间。
There are two time sources in a machine: the CPU's clock and an on-board clock (e.g., real-time clock (RTC), Programmable Interval Timers (PIT), and High Precision Event Timer (HPET)). The first has a resolution of around ~0.5ns (2GHz) and the second is generally programmable down to a period of 1ms (though newer chips (HPET) have higher resolution). Windows uses these periodic ticks to perform certain operations, including updating the system time.
机器中有两个时间源:CPU 的时钟和板载时钟(例如,实时时钟 (RTC)、可编程间隔定时器 (PIT) 和高精度事件定时器 (HPET))。第一个具有约 0.5ns (2GHz) 的分辨率,第二个通常可编程低至 1ms(尽管较新的芯片 (HPET) 具有更高的分辨率)。Windows 使用这些周期性滴答来执行某些操作,包括更新系统时间。
Applications can change this period via timerBeginPeriod; however, this affects the entire system. The OS will check / update regular events at the requested frequency. Under low CPU loads / frequencies, there are idle periods for power savings. At high frequencies, there isn't time to put the processor into low power states. See Timer Resolutionfor further details. Finally, each tick has some overhead and increasing the frequency consumes more CPU cycles.
应用程序可以通过timerBeginPeriod更改此时间段;但是,这会影响整个系统。操作系统将以请求的频率检查/更新常规事件。在低 CPU 负载/频率下,有一些空闲时间可以节省电力。在高频下,没有时间将处理器置于低功耗状态。有关详细信息,请参阅定时器分辨率。最后,每个滴答都有一些开销,增加频率会消耗更多的 CPU 周期。
For higher resolution time, the system time is not maintained to this accuracy, no more than Big Ben has a second hand. Using QueryPerformanceCounter(QPC) or the CPU's ticks (rdtsc) can provide the resolution between the system time ticks. Such an approach was used in the MSDN magazine article Kevin cited. Though these approaches may have drift (e.g., due to frequency scaling), etc and therefore need to be synced to the system time.
对于更高分辨率的时间,系统时间不会保持到这种精度,就像大本钟有秒针一样。使用 QueryPerformanceCounter(QPC) 或 CPU 的滴答 (rdtsc) 可以提供系统时间滴答之间的分辨率。Kevin 引用的 MSDN 杂志文章中使用了这种方法。尽管这些方法可能有漂移(例如,由于频率缩放)等,因此需要与系统时间同步。
回答by Ian Boyd
In Windows, the base of all time is a function called GetSystemTimeAsFiletime
.
在 Windows 中,所有时间的基础是一个名为GetSystemTimeAsFiletime
.
- It returns a structure that is capable of holding a time with 100ns resoution.
- It is kept in UTC
- 它返回一个能够以 100ns 分辨率保持时间的结构。
- 它以UTC格式保存
The FILETIME
structure records the number of 100ns intervals since January 1, 1600; meaning its resolution is limited to 100ns.
该FILETIME
结构记录了自 1600 年 1 月 1 日以来间隔 100ns 的次数;这意味着它的分辨率被限制在 100ns。
This forms our first function:
这形成了我们的第一个函数:
A 64-bit number of 100ns ticks since January 1, 1600 is somewhat unwieldy. Windows provides a handy helper function, FileTimeToSystemTime
that can decode this 64-bit integer into useful parts:
自 1600 年 1 月 1 日以来的 64 位 100ns 滴答数有点笨拙。Windows 提供了一个方便的辅助函数,FileTimeToSystemTime
可以将这个 64 位整数解码为有用的部分:
record SYSTEMTIME {
wYear: Word;
wMonth: Word;
wDayOfWeek: Word;
wDay: Word;
wHour: Word;
wMinute: Word;
wSecond: Word;
wMilliseconds: Word;
}
Notice that SYSTEMTIME
has a built-in resolution limitation of 1ms
请注意,SYSTEMTIME
有一个内置的分辨率限制1ms
Now we have a way to go from FILETIME
to SYSTEMTIME
:
现在我们有办法从FILETIME
到SYSTEMTIME
:
We could write the function to get the current system time as a SYSTEIMTIME
structure:
我们可以编写函数来获取当前系统时间作为一个SYSTEIMTIME
结构:
SYSTEMTIME GetSystemTime()
{
//Get the current system time utc in it's native 100ns FILETIME structure
FILETIME ftNow;
GetSytemTimeAsFileTime(ref ft);
//Decode the 100ns intervals into a 1ms resolution SYSTEMTIME for us
SYSTEMTIME stNow;
FileTimeToSystemTime(ref stNow);
return stNow;
}
Except Windows already wrote such a function for you: GetSystemTime
除了 Windows 已经为您编写了这样的函数: GetSystemTime
Local, rather than UTC
本地,而不是 UTC
Now what if you don't want the current time in UTC. What if you want it in your local time? Windows provides a function to convert a FILETIME
that is in UTC into your local time: FileTimeToLocalFileTime
现在,如果您不想要 UTC 中的当前时间怎么办。如果你想在当地时间呢?Windows 提供了将FILETIME
UTC 中的a 转换为您的本地时间的函数:FileTimeToLocalFileTime
You could write a function that returns you a FILETIME
in localtime already:
您可以编写一个已经FILETIME
在本地时间返回 a 的函数:
FILETIME GetLocalTimeAsFileTime()
{
FILETIME ftNow;
GetSystemTimeAsFileTime(ref ftNow);
//convert to local
FILETIME ftNowLocal
FileTimeToLocalFileTime(ftNow, ref ftNowLocal);
return ftNowLocal;
}
And lets say you want to decode the localFILETIME into a SYSTEMTIME. That's no problem, you can use FileTimeToSystemTime
again:
假设您想将本地FILETIME解码为 SYSTEMTIME。没问题,你可以FileTimeToSystemTime
再次使用:
Fortunately, Windows already provides you a function that returns you the value:
幸运的是,Windows 已经为您提供了一个返回值的函数:
Precise
精确的
There is another consideration. Before Windows 8, the clock had a resolution of around 15ms. In Windows 8 they improved the clock to 100ns (matching the resolution of FILETIME
).
还有另一个考虑。在 Windows 8 之前,时钟的分辨率约为 15 毫秒。在 Windows 8 中,他们将时钟提高到 100ns(与 的分辨率匹配FILETIME
)。
GetSystemTimeAsFileTime
(legacy, 15ms resolution)GetSystemTimeAsPreciseFileTime
(Windows 8, 100ns resolution)
GetSystemTimeAsFileTime
(传统,15 毫秒分辨率)GetSystemTimeAsPreciseFileTime
(Windows 8, 100ns 分辨率)
This means we should always prefer the new value:
这意味着我们应该总是更喜欢新值:
You asked for the time
你问时间
You asked for the time; but you have some choices.
你问了时间;但你有一些选择。
The timezone:
时区:
- UTC (system native)
- Local timezone
- UTC (系统原生)
- 当地时区
The format:
格式:
FILETIME
(system native, 100ns resolution)SYTEMTIME
(decoded, 1ms resolution)
FILETIME
(系统原生,100ns 分辨率)SYTEMTIME
(解码,1ms 分辨率)
Summary
概括
- 100ns resolution:
FILETIME
- UTC:
GetSytemTimeAsPreciseFileTime
(orGetSystemTimeAsFileTime
) - Local: (roll your own)
- UTC:
- 1ms resolution:
SYSTEMTIME
- UTC:
GetSystemTime
- Local:
GetLocalTime
- UTC:
- 100ns分辨率:
FILETIME
- UTC:(
GetSytemTimeAsPreciseFileTime
或GetSystemTimeAsFileTime
) - 本地:(自己动手)
- UTC:(
- 1ms分辨率:
SYSTEMTIME
- 世界标准时间:
GetSystemTime
- 当地的:
GetLocalTime
- 世界标准时间:
回答by David Gausmann
Starting with Windows 8 Microsoft has introduced the new API command GetSystemTimePreciseAsFileTime:
从 Windows 8 开始,Microsoft 引入了新的 API 命令 GetSystemTimePreciseAsFileTime:
https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895%28v=vs.85%29.aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895%28v=vs.85%29.aspx
Unfortunately you can't use that if you create software which must also run on older operating systems.
不幸的是,如果您创建的软件也必须在较旧的操作系统上运行,则不能使用它。
My current solution is as follows, but be aware: The determined time is not exact, it is only near to the real time. The result should always be smaller or equal to the real time, but with a fixed error (unless the computer went to standby). The result has a millisecond resolution. For my purpose it is exact enough.
我目前的解决方案如下,但请注意:确定的时间并不准确,只是接近实际时间。结果应该总是小于或等于实时,但有一个固定的错误(除非计算机进入待机状态)。结果具有毫秒级分辨率。就我的目的而言,它已经足够准确了。
void GetHighResolutionSystemTime(SYSTEMTIME* pst)
{
static LARGE_INTEGER uFrequency = { 0 };
static LARGE_INTEGER uInitialCount;
static LARGE_INTEGER uInitialTime;
static bool bNoHighResolution = false;
if(!bNoHighResolution && uFrequency.QuadPart == 0)
{
// Initialize performance counter to system time mapping
bNoHighResolution = !QueryPerformanceFrequency(&uFrequency);
if(!bNoHighResolution)
{
FILETIME ftOld, ftInitial;
GetSystemTimeAsFileTime(&ftOld);
do
{
GetSystemTimeAsFileTime(&ftInitial);
QueryPerformanceCounter(&uInitialCount);
} while(ftOld.dwHighDateTime == ftInitial.dwHighDateTime && ftOld.dwLowDateTime == ftInitial.dwLowDateTime);
uInitialTime.LowPart = ftInitial.dwLowDateTime;
uInitialTime.HighPart = ftInitial.dwHighDateTime;
}
}
if(bNoHighResolution)
{
GetSystemTime(pst);
}
else
{
LARGE_INTEGER uNow, uSystemTime;
{
FILETIME ftTemp;
GetSystemTimeAsFileTime(&ftTemp);
uSystemTime.LowPart = ftTemp.dwLowDateTime;
uSystemTime.HighPart = ftTemp.dwHighDateTime;
}
QueryPerformanceCounter(&uNow);
LARGE_INTEGER uCurrentTime;
uCurrentTime.QuadPart = uInitialTime.QuadPart + (uNow.QuadPart - uInitialCount.QuadPart) * 10000000 / uFrequency.QuadPart;
if(uCurrentTime.QuadPart < uSystemTime.QuadPart || abs(uSystemTime.QuadPart - uCurrentTime.QuadPart) > 1000000)
{
// The performance counter has been frozen (e. g. after standby on laptops)
// -> Use current system time and determine the high performance time the next time we need it
uFrequency.QuadPart = 0;
uCurrentTime = uSystemTime;
}
FILETIME ftCurrent;
ftCurrent.dwLowDateTime = uCurrentTime.LowPart;
ftCurrent.dwHighDateTime = uCurrentTime.HighPart;
FileTimeToSystemTime(&ftCurrent, pst);
}
}
回答by user3125367
Since we all come here for quick snippets instead of boring explanations, I'll write one:
由于我们都来这里是为了快速片段而不是无聊的解释,我将写一个:
FILETIME t;
GetSystemTimeAsFileTime(&t); // unusable as is
ULARGE_INTEGER i;
i.LowPart = t.dwLowDateTime;
i.HighPart = t.dwHighDateTime;
int64_t ticks_since_1601 = i.QuadPart; // now usable
int64_t us_since_1601 = (i.QuadPart * 1e-1);
int64_t ms_since_1601 = (i.QuadPart * 1e-4);
int64_t sec_since_1601 = (i.QuadPart * 1e-7);
// unix epoch
int64_t unix_us = (i.QuadPart * 1e-1) - 11644473600LL * 1000000;
int64_t unix_ms = (i.QuadPart * 1e-4) - 11644473600LL * 1000;
double unix_sec = (i.QuadPart * 1e-7) - 11644473600LL;
// i.QuadPart is # of 100ns ticks since 1601-01-01T00:00:00Z
// difference to Unix Epoch is 11644473600 seconds (attention to units!)
No idea how drifting performance-counter-based answers went up, don't do slippage bugs, guys.
不知道基于性能计数器的漂移答案是如何上升的,不要做滑点错误,伙计们。
回答by Ben Voigt
GetSystemTimeAsFileTimegives the best precision of any Win32 function for absolute time. QPF/QPC as Joel Clark suggested will give better relative time.
GetSystemTimeAsFileTime为绝对时间提供了任何 Win32 函数的最佳精度。乔尔克拉克建议的 QPF/QPC 将提供更好的相对时间。
回答by Bruno
QueryPerformanceCounter() is built for fine-grained timer resolution.
QueryPerformanceCounter() 是为细粒度计时器分辨率而构建的。
It is the highest resolution timer that the system has to offer that you can use in your application code to identify performance bottlenecks
它是系统必须提供的最高分辨率计时器,您可以在应用程序代码中使用它来识别性能瓶颈
Here is a simple implementation for C# devs:
这是 C# 开发人员的简单实现:
[DllImport("kernel32.dll")]
extern static short QueryPerformanceCounter(ref long x);
[DllImport("kernel32.dll")]
extern static short QueryPerformanceFrequency(ref long x);
private long m_endTime;
private long m_startTime;
private long m_frequency;
public Form1()
{
InitializeComponent();
}
public void Begin()
{
QueryPerformanceCounter(ref m_startTime);
}
public void End()
{
QueryPerformanceCounter(ref m_endTime);
}
private void button1_Click(object sender, EventArgs e)
{
QueryPerformanceFrequency(ref m_frequency);
Begin();
for (long i = 0; i < 1000; i++) ;
End();
MessageBox.Show((m_endTime - m_startTime).ToString());
}
If you are a C/C++ dev, then take a look here: http://support.microsoft.com/kb/815668
如果您是 C/C++ 开发人员,请看这里:http: //support.microsoft.com/kb/815668
回答by Mikhail Edoshin
回答by Chris Kline
I've written up some information about how to implement this quickly and easily, in a manner suitable for most purposes, in my answer to the "Microsecond resolution timestamps on Windows"question.
在我对“Windows 上的微秒分辨率时间戳”问题的回答中,我已经写了一些关于如何以适合大多数目的的方式快速轻松地实现这一点的信息。