Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<chrono>: clock_cast throws an exception under windows7 sp1 #2446

Open
segeter opened this issue Dec 23, 2021 · 5 comments
Open

<chrono>: clock_cast throws an exception under windows7 sp1 #2446

segeter opened this issue Dec 23, 2021 · 5 comments
Labels
chrono C++20 chrono enhancement Something can be improved

Comments

@segeter
Copy link

segeter commented Dec 23, 2021

code:
try { auto timestamp = std::chrono::clock_cast<std::chrono::system_clock>(std::filesystem::last_write_time(entity)); } catch (const std::exception& e) { // Caught exception }

debug:
__std_tzdb_get_time_zones failed because the error code is _Win_error

@fsb4000
Copy link
Contributor

fsb4000 commented Dec 23, 2021

While the STL generally provides all features on all supported versions of Windows, leap seconds and time zones (which change over time) require OS support that was added to Windows 10. Specifically, updating the leap second database requires Windows 10 version 1809 or later, and time zones require icu.dll which is provided by Windows 10 version 1903/19H1 or later. This applies to both client and server OSes; note that Windows Server 2019 is based on Windows 10 version 1809.

See:

  1. clock_cast calls clock_time_conversion

    STL/stl/inc/chrono

    Lines 3584 to 3585 in 9265c51

    return clock_time_conversion<_DestClock, utc_clock>{}(
    clock_time_conversion<utc_clock, _SourceClock>{}(_Time));

2)clock_time_conversion calls utc_clock::to_sys

STL/stl/inc/chrono

Lines 3428 to 3434 in 9265c51

template <>
struct clock_time_conversion<system_clock, utc_clock> {
template <class _Duration>
_NODISCARD sys_time<common_type_t<_Duration, seconds>> operator()(const utc_time<_Duration>& _Utc_time) const {
return utc_clock::to_sys(_Utc_time);
}
};

  1. utc_clock::to_sys calls get_leap_second_info

    STL/stl/inc/chrono

    Lines 3208 to 3211 in 9265c51

    template <class _Duration>
    _NODISCARD static sys_time<common_type_t<_Duration, seconds>> to_sys(const utc_time<_Duration>& _Utc_time) {
    using _CommonType = common_type_t<_Duration, seconds>;
    const auto _Lsi{_CHRONO get_leap_second_info(_Utc_time)};

BOOM.

I'm not a chrono expert. Perhaps something in this sequence of calls is wrong. But in my opinioin it's unfortunate but i's correct.

Now is the holiday period at Microsoft, until January 3 (or 10 for some people). So the response from chrono maintainer may be delayed...

@segeter
Copy link
Author

segeter commented Dec 23, 2021

While the STL generally provides all features on all supported versions of Windows, leap seconds and time zones (which change over time) require OS support that was added to Windows 10. Specifically, updating the leap second database requires Windows 10 version 1809 or later, and time zones require icu.dll which is provided by Windows 10 version 1903/19H1 or later. This applies to both client and server OSes; note that Windows Server 2019 is based on Windows 10 version 1809.

See:

  1. clock_cast calls clock_time_conversion

    STL/stl/inc/chrono

    Lines 3584 to 3585 in 9265c51

    return clock_time_conversion<_DestClock, utc_clock>{}(
    clock_time_conversion<utc_clock, _SourceClock>{}(_Time));
  1. calls clock_time_conversion``utc_clock::to_sys

STL/stl/inc/chrono

Lines 3428 to 3434 in 9265c51

template <>
struct clock_time_conversion<system_clock, utc_clock> {
template <class _Duration>
_NODISCARD sys_time<common_type_t<_Duration, seconds>> operator()(const utc_time<_Duration>& _Utc_time) const {
return utc_clock::to_sys(_Utc_time);
}
};

  1. utc_clock::to_sys calls get_leap_second_info

    STL/stl/inc/chrono

    Lines 3208 to 3211 in 9265c51

    template <class _Duration>
    _NODISCARD static sys_time<common_type_t<_Duration, seconds>> to_sys(const utc_time<_Duration>& _Utc_time) {
    using _CommonType = common_type_t<_Duration, seconds>;
    const auto _Lsi{_CHRONO get_leap_second_info(_Utc_time)};

BOOM.

I'm not a chrono expert. Perhaps something in this sequence of calls is wrong. But in my opinioin it's unfortunate but i's correct.

Now is the holiday period at Microsoft, until January 3 (or 10 for some people). So the response from maintainer may be delayed...chrono

Thanks for your answer.
You are right, I also saw the implementation of tzdb.cpp today. Icu.dll needs to be loaded, but there is no icu.dll and its dependent dll under windows7.

@MattStephanson
Copy link
Contributor

Yes, the clock conversions that need leap second info take it from the tzdb_list, which will throw during construction if icu.dll isn't found. Probably the easiest approach would be to create a tzdb without any time zones, but that could break existing code that expects an exception in that case. (I find [time.zone.db] unclear or silent about whether that would be a "valid" tzdb or if current_zone() may return nullptr or throw.) We could also have an internal function that just generates leap second data if a tzdb isn't available, but it would have to either be recreated every time it's needed or cached in a singleton in the manner of tzdb_list.

@cpplearner
Copy link
Contributor

See also #1911

@StephanTLavavej StephanTLavavej added bug Something isn't working chrono C++20 chrono labels Jan 12, 2022
@doomlaur
Copy link

For now we built a wrapper function to benefit from high-precision file write times from std::filesystem, while still supporting older versions of Windows:

// Define these somewhere
using file_duration = std::chrono::duration<long long, std::filesystem::file_time_type::period>;
using file_time_point = std::chrono::time_point<std::chrono::system_clock, file_duration>;

// Write a wrapper function that avoids clock_casts
// Note: leap seconds are NOT considered, as they require a time zone database!
std::error_code ec;
auto file_time = std::filesystem::last_write_time(path, ec);
auto last_write_time = std::chrono::time_point_cast<file_duration>(file_time - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chrono C++20 chrono enhancement Something can be improved
Projects
None yet
Development

No branches or pull requests

6 participants