-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Check leap second awareness and interpret
FILETIME
accordingly
Windows 10 1809 and Windows Server 2019 introduced support for leap seconds (enabled by default, could be disabled system-wide). When leap seconds are enabled, leap seconds after July 2018 are included in the tick count of `FILETIME`. This is different from the old behavior that `FILETIME` doesn't count leap seconds. In the future, the same `FILETIME` value could represent different time points a few seconds apart depending on whether leap second support is available and enabled. This PR detects whether leap second support is enabled on the system by performing trial conversion from `SYSTEMTIME` to `FILETIME`. The following functions, which depend on interpretation of `FILETIME`, are modified to correctly handle `FILETIME`: - `file_clock::now()` - `file_clock` conversions - `file_clock` I/O - `system_clock::now()`, which gets the current `FILETIME` internally - In C++20 mode, `system_clock::now()` uses C++20 <chrono> features to convert the current `FILETIME` to `sys_time`. - In C++14/C++17 mode, `system_clock::now()` calls `FileTimeToSystemTime` to determine how Windows interprets the current `FILETIME`.
- Loading branch information
1 parent
f675d68
commit 119d474
Showing
9 changed files
with
348 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// xtime0.h internal header | ||
|
||
// Copyright (c) Microsoft Corporation. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
||
// This must be as small as possible, because its contents are | ||
// injected into the msvcprt.lib and msvcprtd.lib import libraries. | ||
// Do not include or define anything else here. | ||
// In particular, basic_string must not be included here. | ||
|
||
#pragma once | ||
#ifndef _XTIME0_H | ||
#define _XTIME0_H | ||
|
||
#include <yvals_core.h> | ||
|
||
#pragma pack(push, _CRT_PACKING) | ||
#pragma warning(push, _STL_WARNING_LEVEL) | ||
#pragma warning(disable : _STL_DISABLED_WARNINGS) | ||
_STL_DISABLE_CLANG_WARNINGS | ||
#pragma push_macro("new") | ||
#undef new | ||
|
||
_EXTERN_C | ||
|
||
// clang-format off | ||
struct __std_win_system_time { // typedef struct _SYSTEMTIME { | ||
unsigned short _Year; // WORD wYear; | ||
unsigned short _Month; // WORD wMonth; | ||
unsigned short _Day_of_week; // WORD wDayOfWeek; | ||
unsigned short _Day; // WORD wDay; | ||
unsigned short _Hour; // WORD wHour; | ||
unsigned short _Minute; // WORD wMinute; | ||
unsigned short _Second; // WORD wSecond; | ||
unsigned short _Milliseconds; // WORD wMilliseconds; | ||
}; // } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; | ||
// clang-format on | ||
|
||
// Gets the number of 100 ns ticks since 1601-01-01. | ||
// Leap seconds before 2018-07-01 are excluded. | ||
// Leap seconds since 2018-07-01 may or may not be included depending on OS version and system configuration. | ||
_NODISCARD long long __stdcall __std_file_clock_now() noexcept; | ||
|
||
// Gets the number of 100 ns ticks since 1970-01-01, excluding leap seconds. | ||
// If this function is called during a leap second insertion, and the system is leap second aware, | ||
// the largest representable value before the leap second insertion is returned. | ||
_NODISCARD long long __stdcall __std_system_clock_now_cpp14() noexcept; | ||
|
||
// Calls Windows SystemTimeToFileTime | ||
_NODISCARD long long __stdcall __std_system_time_to_file_time(const __std_win_system_time* _System_time) noexcept; | ||
|
||
_END_EXTERN_C | ||
|
||
#pragma pop_macro("new") | ||
_STL_RESTORE_CLANG_WARNINGS | ||
#pragma warning(pop) | ||
#pragma pack(pop) | ||
|
||
#endif // defined(_XTIME0_H) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
||
// This must be as small as possible, because its contents are | ||
// injected into the msvcprt.lib and msvcprtd.lib import libraries. | ||
// Do not include or define anything else here. | ||
// In particular, basic_string must not be included here. | ||
|
||
#include <chrono> | ||
#include <cstdlib> | ||
#include <xtime0.h> | ||
|
||
#include "awint.hpp" | ||
#include "xtime_inl.hpp" | ||
|
||
_EXTERN_C | ||
|
||
_NODISCARD long long __stdcall __std_file_clock_now() noexcept { | ||
return file_clock_now(); | ||
} | ||
|
||
_NODISCARD long long __stdcall __std_system_clock_now_cpp14() noexcept { | ||
return system_clock_now_cpp14(); | ||
} | ||
|
||
_NODISCARD long long __stdcall __std_system_time_to_file_time( | ||
const __std_win_system_time* const _System_time) noexcept { | ||
FILETIME ft; | ||
if (SystemTimeToFileTime(reinterpret_cast<const SYSTEMTIME*>(_System_time), &ft) == FALSE) { | ||
_STL_ASSERT(false, "SystemTimeToFileTime failed"); | ||
return -1; | ||
} | ||
|
||
return ((static_cast<long long>(ft.dwHighDateTime)) << 32) + static_cast<long long>(ft.dwLowDateTime); | ||
} | ||
|
||
_END_EXTERN_C |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
||
// This must be as small as possible, because its contents are | ||
// injected into the msvcprt.lib and msvcprtd.lib import libraries. | ||
// Do not include or define anything else here. | ||
// In particular, basic_string must not be included here. | ||
|
||
#pragma once | ||
#ifndef XTIME_INL_HPP | ||
#define XTIME_INL_HPP | ||
|
||
#include <chrono> | ||
#include <cstdlib> | ||
#include <xtime0.h> | ||
|
||
#include "awint.hpp" | ||
|
||
static_assert(sizeof(__std_win_system_time) == sizeof(SYSTEMTIME)); | ||
static_assert(alignof(__std_win_system_time) == alignof(SYSTEMTIME)); | ||
|
||
_NODISCARD inline long long file_clock_now() noexcept { | ||
FILETIME ft; | ||
__crtGetSystemTimePreciseAsFileTime(&ft); | ||
return ((static_cast<long long>(ft.dwHighDateTime)) << 32) + static_cast<long long>(ft.dwLowDateTime); | ||
} | ||
|
||
_NODISCARD inline long long system_clock_now_cpp14() noexcept { | ||
using namespace std::chrono; | ||
constexpr int ticks_per_sec = 10'000'000u; | ||
static_assert(system_clock::duration{ticks_per_sec} == 1s); | ||
|
||
// check how Windows interprets the current second | ||
const long long ticks = file_clock_now(); | ||
auto sub_sec_ticks = static_cast<int>(ticks % ticks_per_sec); | ||
const long long sec_ticks = ticks - sub_sec_ticks; | ||
|
||
const FILETIME sec_ft{ | ||
.dwLowDateTime = static_cast<DWORD>(sec_ticks), | ||
.dwHighDateTime = static_cast<DWORD>(sec_ticks >> 32), | ||
}; | ||
SYSTEMTIME st; | ||
if (FileTimeToSystemTime(&sec_ft, &st) == FALSE) { | ||
_STL_ASSERT(false, "FileTimeToSystemTime failed"); | ||
std::abort(); | ||
} | ||
|
||
if (st.wSecond == 60) { | ||
// during leap second insertion | ||
// system is leap second aware | ||
// process is leap second aware | ||
st.wSecond = 59; | ||
sub_sec_ticks = ticks_per_sec - 1; | ||
} else if (st.wMilliseconds != 0) { | ||
_STL_INTERNAL_CHECK(st.wSecond == 59 && st.wMilliseconds == 500); | ||
|
||
if (st.wSecond == 59 && st.wMilliseconds == 500) { | ||
// during leap second insertion | ||
// system is leap second aware | ||
// process is leap second unaware, 23:59:60.000 UTC is reported as 23:59:59.500 in SYSTEMTIME | ||
sub_sec_ticks = ticks_per_sec - 1; | ||
} else { | ||
// fail-safe fallback in case leap second smearing behavior changes in future Windows versions | ||
constexpr int ticks_per_ms = ticks_per_sec / 1000; | ||
|
||
const FILETIME ft{ | ||
.dwLowDateTime = static_cast<DWORD>(ticks), | ||
.dwHighDateTime = static_cast<DWORD>(ticks >> 32), | ||
}; | ||
if (FileTimeToSystemTime(&ft, &st) == FALSE) { | ||
_STL_ASSERT(false, "FileTimeToSystemTime failed"); | ||
std::abort(); | ||
} | ||
|
||
if (st.wSecond == 60) { | ||
st.wSecond = 59; | ||
sub_sec_ticks = ticks_per_sec - 1; | ||
} else { | ||
sub_sec_ticks = st.wMilliseconds * ticks_per_ms; | ||
} | ||
} | ||
} | ||
|
||
const system_clock::time_point now = | ||
sys_days{year{st.wYear} / month{st.wMonth} / day{st.wDay}} | ||
+ (hours{st.wHour} + minutes{st.wMinute} + seconds{st.wSecond} + system_clock::duration{sub_sec_ticks}); | ||
return now.time_since_epoch().count(); | ||
} | ||
|
||
#endif // defined(XTIME_INL_HPP) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters