diff --git a/stl/inc/chrono b/stl/inc/chrono index 0035ee71026..7e49b82e144 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -5465,28 +5465,40 @@ namespace chrono { _STL_INTERNAL_CHECK(false); } - template - void _Write_seconds(basic_ostream<_CharT, _Traits>& _Os, const hh_mm_ss<_Duration>& _Val) { - _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:02}"), _Val.seconds().count()); - if constexpr (hh_mm_ss<_Duration>::fractional_width > 0) { + template + void _Write_fractional_seconds( + basic_ostream<_CharT, _Traits>& _Os, const seconds& _Seconds, const _Precision& _Subseconds) { + _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:02}"), _Seconds.count()); + if constexpr (_Fractional_width > 0) { _Os << _STD use_facet>(_Os.getloc()).decimal_point(); - if constexpr (treat_as_floating_point_v::precision::rep>) { - _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"), _STD floor(_Val.subseconds().count()), - _Val.fractional_width); - } else { + if constexpr (treat_as_floating_point_v) { _Os << _STD format( - _STATICALLY_WIDEN(_CharT, "{:0{}}"), _Val.subseconds().count(), _Val.fractional_width); + _STATICALLY_WIDEN(_CharT, "{:0{}.0f}"), _STD floor(_Subseconds.count()), _Fractional_width); + } else { + _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:0{}}"), _Subseconds.count(), _Fractional_width); } } } + template + void _Write_seconds(basic_ostream<_CharT, _Traits>& _Os, const hh_mm_ss<_Duration>& _Val) { + _Write_fractional_seconds::fractional_width>(_Os, _Val.seconds(), _Val.subseconds()); + } + template void _Write_seconds(basic_ostream<_CharT, _Traits>& _Os, const time_point<_Clock, _Duration>& _Val) { if constexpr (is_same_v<_Clock, utc_clock>) { - if (_CHRONO get_leap_second_info(_Val).is_leap_second) { - _Os << _STATICALLY_WIDEN(_CharT, "60"); - return; + const auto _Lsi = _CHRONO get_leap_second_info(_Val); + const auto _Dp = + _CHRONO floor(_Val - _Lsi.elapsed) + _Lsi.elapsed - seconds{_Lsi.is_leap_second ? 1 : 0}; + const hh_mm_ss _Hms{_Val - _Dp}; + constexpr auto _Fractional_width = decltype(_Hms)::fractional_width; + if (_Lsi.is_leap_second) { + _Write_fractional_seconds<_Fractional_width>(_Os, _Hms.seconds() + seconds{60}, _Hms.subseconds()); + } else { + _Write_fractional_seconds<_Fractional_width>(_Os, _Hms.seconds(), _Hms.subseconds()); } + return; } const auto _Dp = _CHRONO floor(_Val); _Write_seconds(_Os, hh_mm_ss{_Val - _Dp}); diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp index 4cdaac2844f..3c14b7c28f5 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp @@ -250,6 +250,34 @@ void test_clock_formatter() { throw_helper(STR("{:%Z %z %Oz %Ez}"), local_seconds{}); assert(format(STR("{:%S}"), utc_clock::from_sys(get_tzdb().leap_seconds.front().date()) - 1s) == STR("60")); + assert(format(STR("{:%F %T}"), utc_clock::from_sys(get_tzdb().leap_seconds.front().date())) + == STR("1972-07-01 00:00:00")); + assert(format(STR("{:%F %T}"), utc_clock::from_sys(sys_days{January / 9 / 2014} + 12h + 35min + 34s)) + == STR("2014-01-09 12:35:34")); + assert(format(STR("{:%F %T}"), utc_clock::from_sys(get_tzdb().leap_seconds.front().date()) - 500ms) + == STR("1972-06-30 23:59:60.500")); + + // Test an ordinary day. + const auto utc_2021_05_04 = utc_clock::from_sys(sys_days{2021y / May / 4}); + + // This is both the last day of a leap year (366th day) and the day of a leap second insertion. + const auto utc_2016_12_31 = utc_clock::from_sys(sys_days{2016y / December / 31}); + + for (const auto& h : {0h, 1h, 7h, 22h, 23h}) { // Accelerate testing; 24 * 60 * 61 iterations would be a lot. + for (const auto& m : {0min, 1min, 7min, 58min, 59min}) { + for (const auto& s : {0s, 1s, 7s, 58s, 59s, 60s}) { + if (s != 60s) { + assert(format(STR("{:%F %T}"), utc_2021_05_04 + h + m + s) + == format(STR("2021-05-04 {:02}:{:02}:{:02}"), h.count(), m.count(), s.count())); + } + + if ((h == 23h && m == 59min) || s != 60s) { + assert(format(STR("{:%F %T}"), utc_2016_12_31 + h + m + s) + == format(STR("2016-12-31 {:02}:{:02}:{:02}"), h.count(), m.count(), s.count())); + } + } + } + } } template