c++windowstimefiletime

Convert 100-nanoseconds to millisecond confusion


NOTE: This is likely a question about flawed math, rather then a question about the a windows system call as described in the question.

We are working with with the GetSystemTimeAsFileTime() win32 call, and seeing what I think are strange results and was looking for some clarification. From MSDN on the FILETIME structure https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284%28v=vs.85%29.aspx

Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).

According to our read of this description, the value returned is the number of 10e-8 interval seconds. Assuming this is correct, then the following function should return the system time in milliseconds.

DWORD get_milli_time() {
    FILETIME f;
    ::GetSystemTimeAsFileTime(&f);
    __int64 nano = (__int64(f.dwHighDateTime) << 32LL)
                  + __int64(f.dwLowDateTime);
    return DWORD(nano / 10e5);
    }

A simple unittest however shows this is incorrect, the below code prints "Failed":

DWORD start = get_milli_time();
::Sleep(5000);  // sleep for 5-seconds
DWORD end = get_milli_time();
// test for reasonable sleep variance (4.9 - 5.1 secs)
if ((end - start) < 4900 || (end - start) > 5100) {
    printf("Failed\n");
    }

According to this SO post Getting the current time (in milliseconds) from the system clock in Windows?, the correct results can be achieved by changing our division to:

return DWORD(nano / 10e3);

If we use this value, we get the correct result, but I can't understand why.

It seems to me that to convert from 10e-8 to 10e-3, we should divide by 10e5. This would seem to be borne out by the following calculation:

printf("%f\n", log10(10e-3 / 10e-8));

Which returns 5 (as I expected).

But somehow I'm wrong -- but I'll be darned if I can see where I've gone wrong.


Solution

  • Your math is indeed flawed, and so is your understanding of the "working" code.

    There are 107 100-nanosecond intervals in a second, 104 in a millisecond. In floating-point notation, this is 1.0e4. 10e3 is a weird way of writing 1e4.

    The "right" (in a sense of most efficient while remaining expressive) code would be

    return DWORD(hundrednano * 1.0e-4);