diff --git a/stl/inc/chrono b/stl/inc/chrono index 565b831dd5..48e829f56a 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -18,6 +18,7 @@ #if _HAS_CXX20 #include #include +#include #include #include #include @@ -2457,13 +2458,22 @@ namespace chrono { template _NODISCARD static sys_time> to_sys(const utc_time<_Duration>& _Utc_time) { + using _CT = common_type_t<_Duration, seconds>; const auto _Lsi{get_leap_second_info(_Utc_time)}; - sys_time> _Sys_time{_Utc_time.time_since_epoch() - _Lsi.elapsed}; + _CT _Ticks; if (_Lsi.is_leap_second) { - constexpr auto _Delta{seconds{1} - common_type_t<_Duration, seconds>{1}}; - _Sys_time = _CHRONO floor(_Sys_time) + _Delta; + const auto _Leap_sec_minus_one = _CHRONO floor(_Utc_time.time_since_epoch()) - _Lsi.elapsed; + if constexpr (is_integral_v) { + constexpr auto _Delta{seconds{1} - _CT{1}}; + _Ticks = _Leap_sec_minus_one + _Delta; + } else { + const auto _Leap_sec_begin = _CHRONO ceil<_CT>(_Leap_sec_minus_one + seconds{1}); + _Ticks = _CT{_STD nextafter(_Leap_sec_begin.count(), typename _CT::rep{0})}; + } + } else { + _Ticks = _Utc_time.time_since_epoch() - _Lsi.elapsed; } - return _Sys_time; + return sys_time<_CT>{_Ticks}; } template diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp index d2d1eff279..75417402b0 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -173,10 +174,11 @@ constexpr bool operator==(const leap_second_info& lhs, const leap_second_info& r return lhs.is_leap_second == rhs.is_leap_second && lhs.elapsed == rhs.elapsed; } +template void test_leap_second_info(const leap_second& leap, seconds accum) { const bool is_positive = (leap.value() == 1s); // First UTC time when leap is counted, before insertion of a positive leap, after insertion of a negative one. - const utc_seconds utc_leap{leap.date().time_since_epoch() + accum + (is_positive ? 0s : -1s)}; + const utc_time> utc_leap{leap.date().time_since_epoch() + accum + (is_positive ? 0s : -1s)}; auto lsi = get_leap_second_info(utc_leap - 1s); assert(lsi == (leap_second_info{false, accum})); @@ -197,11 +199,19 @@ void test_leap_second_info(const leap_second& leap, seconds accum) { template void test_utc_clock_to_sys(const leap_second& leap) { - auto u = utc_clock::from_sys(leap.date() - Duration{1}); // just before leap second + sys_time before_leap; + if constexpr (is_integral_v) { + before_leap = leap.date() - Duration{1}; + } else { + before_leap = + sys_time{Duration{nextafter(leap.date().time_since_epoch().count(), typename Duration::rep{0})}}; + } + + auto u = utc_clock::from_sys(before_leap); // just before leap second assert(utc_clock::from_sys(utc_clock::to_sys(u)) == u); if (leap.value() == 1s) { u += Duration{1}; - assert(utc_clock::to_sys(u) == leap.date() - Duration{1}); // during + assert(utc_clock::to_sys(u) == before_leap); // during } else { assert(utc_clock::from_sys(utc_clock::to_sys(u)) == u); } @@ -342,11 +352,17 @@ void test_gps_tai_clocks_utc() { int main() { test_leap_second(); + // This is the only time duration a leap second insertion that can be represented by a duration. + assert(utc_clock::to_sys(utc_time>{duration{78796800.0f}}).time_since_epoch().count() + == nextafter(78796800.0f, 0.0f)); + seconds offset{0}; for (const auto& leap : get_tzdb().leap_seconds) { - test_leap_second_info(leap, offset); + test_leap_second_info(leap, offset); + test_leap_second_info(leap, offset); test_utc_clock_to_sys(leap); test_utc_clock_to_sys(leap); + test_utc_clock_to_sys>(leap); test_file_clock_from_utc(leap); test_file_clock_from_utc(leap); test_utc_clock_from_sys(leap, offset); @@ -371,9 +387,11 @@ int main() { offset = 0s; for (const auto& leap : get_tzdb().leap_seconds) { - test_leap_second_info(leap, offset); + test_leap_second_info(leap, offset); + test_leap_second_info(leap, offset); test_utc_clock_to_sys(leap); test_utc_clock_to_sys(leap); + test_utc_clock_to_sys>(leap); test_file_clock_from_utc(leap); test_file_clock_from_utc(leap); test_utc_clock_from_sys(leap, offset); @@ -396,9 +414,11 @@ int main() { offset = 0s; for (const auto& leap : get_tzdb().leap_seconds) { - test_leap_second_info(leap, offset); + test_leap_second_info(leap, offset); + test_leap_second_info(leap, offset); test_utc_clock_to_sys(leap); test_utc_clock_to_sys(leap); + test_utc_clock_to_sys>(leap); test_file_clock_from_utc(leap); test_file_clock_from_utc(leap); test_utc_clock_from_sys(leap, offset);