microsoft / STL

MSVC's implementation of the C++ Standard Library.
Other
10.16k stars 1.5k forks source link

<chrono>: system_clock could be off after a future leap second #1520

Open statementreply opened 3 years ago

statementreply commented 3 years ago

Describe the bug

Since Windows 10 1809 and Windows Server 2019, FILETIME includes leap seconds after 2018-06 (configurable system-wide, enabled by default), and will no longer be a constant offset from system_clock. system_clock::now needs to be updated to account for future leap seconds, if enabled on the system.

Command-line test case

  1. Run the following command once as administrator. Note that this inserts a fake leap second (2020-11-30T23:59:60Z). The system clock and file modification times after 2020-11-30 will be off by 1 second.

    C:\WINDOWS\system32>w32tm /leapseconds /add:+2020-11-30T23:59:59 /force /testmode
    成功地执行了命令。

    The following command can be used to check the status of leap seconds.

    C:\WINDOWS\system32>w32tm /leapseconds /getstatus /verbose
    [闰秒]
    Enabled: 1 (Local)
    Number of Leap Seconds (after June 2018): 1 (Local)
    Leap Seconds List (Local):
    +2020-11-30T23:59:59
  2. Run the test case.

    D:\Temp>type leap_second_2.cpp
    #include <Windows.h>
    #include <chrono>
    #include <cstdio>
    
    using namespace std;
    using namespace std::chrono;
    
    int main() {
       SYSTEMTIME win_sys_time;
       GetSystemTime(&win_sys_time);
    
       const auto stl_sys_time = system_clock::now();
       const auto stl_total = stl_sys_time.time_since_epoch();
       const auto stl_days = floor<duration<int, ratio<86400>>>(stl_total);
       const auto stl_hours = floor<duration<int, ratio<3600>>>(stl_total - stl_days);
       const auto stl_minutes = floor<duration<int, ratio<60>>>(stl_total - stl_days - stl_hours);
       const auto stl_seconds = floor<duration<int>>(stl_total - stl_days - stl_hours - stl_minutes);
       const auto stl_100ns =
           floor<duration<int, ratio<1, 10'000'000>>>(stl_total - stl_days - stl_hours - stl_minutes - stl_seconds);
    
       printf("Windows: %.4d-%.2d-%.2d %.2d:%.2d:%.2d.%.3d\n", win_sys_time.wYear, win_sys_time.wMonth, win_sys_time.wDay,
           win_sys_time.wHour, win_sys_time.wMinute, win_sys_time.wSecond, win_sys_time.wMilliseconds);
       printf("    STL: %10d %.2d:%.2d:%.2d.%.7d\n", stl_days.count(), stl_hours.count(), stl_minutes.count(),
           stl_seconds.count(), stl_100ns.count());
    }
    D:\Temp>cl /EHsc /W4 /WX /std:c++latest leap_second_2.cpp
    Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29617 for x64
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /std:c++latest is provided as a preview of language features from the latest C++
    working draft, and we're eager to hear about bugs and suggestions for improvements.
    However, note that these features are provided as-is without support, and subject
    to changes or removal as the working draft evolves. See
    https://go.microsoft.com/fwlink/?linkid=2045807 for details.
    
    leap_second_2.cpp
    Microsoft (R) Incremental Linker Version 14.28.29617.0
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /out:leap_second_2.exe
    leap_second_2.obj
    
    D:\Temp>.\leap_second_2.exe
    Windows: 2020-12-09 06:38:33.802
       STL:      18605 06:38:34.8027188
  3. After testing, run the following command as administrator and reboot to revert the fake leap second.

    C:\WINDOWS\system32>w32tm /leapseconds /remove:+2020-11-30T23:59:59 /force /testmode
    成功地执行了命令。

Expected behavior

GetSystemTime and system_clock::now should return the same time.

STL version

Microsoft Visual Studio Community 2019 Preview
版本 16.9.0 Preview 2.0

Additional context

Related to implementation of C++20 file_clock::to_sys xor file_clock::to_utc.

CaseyCarter commented 3 years ago

Thanks for the detailed report, @Statementreply!