The following paragraph has confused me:
From the article: Acquiring high-resolution time stamps
When you need time stamps with a resolution of 1 microsecond or better and you don't need the time stamps to be synchronized to an external time reference, choose QueryPerformanceCounter, KeQueryPerformanceCounter, or KeQueryInterruptTimePrecise. When you need UTC-synchronized time stamps with a resolution of 1 microsecond or better, choose GetSystemTimePreciseAsFileTime or KeQuerySystemTimePrecise.
What does the phrase " to be synchronized to an external time reference" exactly means here? What I learn is this:
Is this assumption correct?
The "current" time returned by various Windows functions doesn't always count up at a rate of 60 seconds every minute.
Sometimes Windows intentionally has the clock going a little bit slower, or a little bit faster:
It does this rather than having your clock suddenly JUMP, and now your logfiles have temporal anomalies.
You can use GetSystemTimeAdjustment
to see if Windows is currently ticking your clock faster or slower, or at the nominal rate. For example, on my computer right now:
But if your clock is too far away from the correct time, Windows will just BONK your time to the correct time.
So the times returned by:
Function | Return type | Resolution | Timezone |
---|---|---|---|
GetLocalTime |
SYSTEM_TIME (1ms) |
~10-15 ms | Local |
GetSystemTime |
SYSTEM_TIME (1ms) |
~10-15 ms | UTC |
GetSystemTimeAsFileTime |
FILE_TIME (0.1us) |
~10-15 ms | UTC |
GetSystemTimePreciseAsFileTime |
FILE_TIME (0.1us) |
0.1 us | UTC |
Can all run fast, slow, or jump around, as your clock jumps around. While QueryPerformanceCounter will never speed up or slow down. It always counts up at exactly the rate of 60s/min.
Function | Return type | Resolution | Timezone |
---|---|---|---|
GetLocalTime |
SYSTEM_TIME (1ms) |
~10-15 ms | Local |
GetSystemTime |
SYSTEM_TIME (1ms) |
~10-15 ms | UTC |
GetSystemTimeAsFileTime |
FILE_TIME (0.1us) |
~10-15 ms | UTC |
GetSystemTimePreciseAsFileTime |
FILE_TIME (0.1us) |
0.1 us | UTC |
GetTickCount |
Int32 (1ms) |
~10-15 ms | n/a |
GetTickCount64 |
Int64 (1ms) |
~10-15 ms | n/a |
QueryPerformanceCounter |
Int64 (ticks) |
0.1 us | n/a |
As long as your computer's clock is not currently undergoing SystemTimeAdjustment
, the elapsed intervals measured by:
will both:
For accurate time measurements these are the two functions you should use. The question, which one do you care for the task:
GetSystemTimeAsPreciseFileTime: high resolution measurement of "now"
QueryPerformanceCounter: high resolution measurement of "elapsed time"
It should be noted that the SYSTEM_TIME
structure returned by GetLocalTime
and GetSystemTime
are inherently limited to millisecond precision. There's no way for GetSystemTime
to give you sub-millisecond resolution, simply because the return type has no place to give you microseconds:
struct SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds; //<---- that's the limit
}
You should only use SYSTEM_TIME
when you want Windows to break a time for you down into years, months, days, hours, minutes, seconds. The FILE_TIME
structure on the other hand as an ultimate precision of 100ns (0.1 us).
In the language i use, we use a DateTime
that is a Double
precision floating point, where:
This is the datetime scheme used by COM, OLE, Delphi, VB, Excel, Lotus 123; and similar to the datetime scheme used by SQL Server (although they use 1/1/1900 rather than 12/30/1899)
DateTime UtcNowPrecise()
{
const UInt64 OA_ZERO_TICKS = 94353120000000000; //12/30/1899 12:00am in ticks
const UInt64 TICKS_PER_DAY = 864000000000; //ticks per day
FILE_TIME ft;
GetSystemTimePreciseAsFileTime(out ft);
ULARGE_INTEGER dt; //needed to avoid alignment faults
dt.LowPart = ft.dwLowDateTime;
dt.HighPart = ft.dwHighDateTime;
return (dt.QuadPart - OA_ZERO_TICKS) / TICKS_PER_DAY;
}
DateTime NowPrecise()
{
const UInt64 OA_ZERO_TICKS = 94353120000000000; //12/30/1899 12:00am in ticks
const UInt64 TICKS_PER_DAY = 864000000000; //ticks per day
FILE_TIME ft;
GetSystemTimePreciseAsFileTime(out ft);
//Convert from UTC to local
FILE_TIME ftLocal;
if (!FileTimeToLocalFileTime(ft, ref ftLocal))
RaiseLastNativeError();
ULARGE_INTEGER dt; //needed to avoid alignment faults
dt.LowPart = ftLocal.dwLowDateTime;
dt.HighPart = ftLocal.dwHighDateTime;
return (dt.QuadPart - OA_ZERO_TICKS) / TICKS_PER_DAY;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With