[libcxx] r290803 - chrono: implement a Windows version of system_clock::now
Howard Hinnant via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 1 13:09:38 PST 2017
On Jan 1, 2017, at 3:20 PM, Saleem Abdulrasool via cfe-commits <cfe-commits at lists.llvm.org> wrote:
>
> Author: compnerd
> Date: Sun Jan 1 14:20:41 2017
> New Revision: 290803
>
> URL: http://llvm.org/viewvc/llvm-project?rev=290803&view=rev
> Log:
> chrono: implement a Windows version of system_clock::now
>
> system_clock::now is not entirely straight forward on Windows, which
> does not have a clock_gettime function.
>
> GetSystemTimeAsFileTime gives us the value relative to the NT epoch (Jan
> 1 1601) rather than the Unix epoch (Jan 1 1970). However, this function
> has a low resolution (~10ms). Newer versions of Windows provide
> GetSystemTimePreciseAsFileTime which gives us a much more accurate time
> (<1us). Unfortunately, the latter is only available on Windows 8+ when
> targeting desktop apps.
>
> Modified:
> libcxx/trunk/src/chrono.cpp
>
> Modified: libcxx/trunk/src/chrono.cpp
> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/chrono.cpp?rev=290803&r1=290802&r2=290803&view=diff
> ==============================================================================
> --- libcxx/trunk/src/chrono.cpp (original)
> +++ libcxx/trunk/src/chrono.cpp Sun Jan 1 14:20:41 2017
> @@ -12,9 +12,18 @@
> #include "system_error" // __throw_system_error
> #include <time.h> // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME
>
> +#if defined(_WIN32)
> +#define WIN32_LEAN_AND_MEAN
> +#define VC_EXTRA_LEAN
> +#include <Windows.h>
> +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
> +#include <winapifamily.h>
> +#endif
> +#else
> #if !defined(CLOCK_REALTIME)
> #include <sys/time.h> // for gettimeofday and timeval
> #endif
> +#endif
>
> #if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(CLOCK_MONOTONIC)
> #if __APPLE__
> @@ -36,6 +45,28 @@ const bool system_clock::is_steady;
> system_clock::time_point
> system_clock::now() _NOEXCEPT
> {
> +#if defined(_WIN32)
> + // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970. The difference
> + // in nanoseconds is the windows epoch offset.
> + static const constexpr __int64 kWindowsEpochOffset = 0x19db1ded53e8000;
This is the correct difference, but the comment is wrong. It isn’t nanoseconds. It is 100ns units.
> +
> + FILETIME ftSystemTime;
> +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
> +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
> + GetSystemTimePreciseAsFileTime(&ftSystemTime);
> +#else
> + GetSystemTimeAsFileTime(&ftSystemTime);
> +#endif
> +#else
> + GetSystemTimeAsFileTime(&ftSystemTime);
> +#endif
> + __int64 llWinTimeNS =
> + ((static_cast<__int64>(ftSystemTime.dwHighDateTime) << 32) |
> + static_cast<__int64>(ftSystemTime.dwLowDateTime)) *
> + 100;
The * 100 will overflow. The * 100 converts 100ns to ns. ns has a signed 64bit range of +/- 292 years, which is greater than the difference between the two epochs.
> + return time_point(duration_cast<duration>(
> + (nanoseconds(llWinTimeNS - kWindowsEpochOffset))));
It really isn’t desirable to bounce this off of nanoseconds because of the overflow.
> +#else
> #ifdef CLOCK_REALTIME
> struct timespec tp;
> if (0 != clock_gettime(CLOCK_REALTIME, &tp))
> @@ -46,6 +77,7 @@ system_clock::now() _NOEXCEPT
> gettimeofday(&tv, 0);
> return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
> #endif // CLOCK_REALTIME
> +#endif
> }
Thank you for preserving the 1970 epoch. Though not currently specified by the standard, it is very important. And hopefully will be specified by a future standard.
Here is code written by Billy O’Neal (MS) doing the conversion you’re looking for:
https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes#FILETIME
It has no intermediate results with precision finer than 100ns. The range of the 64bit 100ns unit goes out to +/- 29 thousand years.
Howard
More information about the cfe-commits
mailing list