[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