diff --git a/stl/inc/chrono b/stl/inc/chrono index a178fe500a1..9ffe4b06af6 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -774,6 +774,19 @@ namespace chrono { return _Rnext; } + template + void _Write_unit_suffix(basic_ostream<_CharT, _Traits>& _Os) { + constexpr auto _Suffix = _Get_literal_unit_suffix<_CharT, _Period>(); + if constexpr (_Suffix == nullptr) { + _CharT _Buffer[2 * (numeric_limits::digits10 + 1) + 5] = {}; // 2 numbers + "[/]s\0" + const _CharT* const _Begin = + _Get_general_unit_suffix<_CharT>(_STD end(_Buffer), _Period::num, _Period::den); + _Os << _Begin; + } else { + _Os << _Suffix; + } + } + template basic_ostream<_CharT, _Traits>& operator<<( basic_ostream<_CharT, _Traits>& _Os, const duration<_Rep, _Period>& _Dur) { @@ -782,16 +795,7 @@ namespace chrono { _Sstr.imbue(_Os.getloc()); _Sstr.precision(_Os.precision()); _Sstr << _Dur.count(); - - constexpr auto _Suffix = _Get_literal_unit_suffix<_CharT, _Period>(); - if constexpr (_Suffix == nullptr) { - _CharT _Buffer[2 * (numeric_limits::digits10 + 1) + 5] = {}; // 2 numbers + "[/]s\0" - const _CharT* const _Begin = - _Get_general_unit_suffix<_CharT>(_STD end(_Buffer), _Period::num, _Period::den); - _Sstr << _Begin; - } else { - _Sstr << _Suffix; - } + _Write_unit_suffix<_Period>(_Sstr); return _Os << _Sstr.str(); } @@ -5470,6 +5474,12 @@ namespace chrono { _Write_seconds(_Os, hh_mm_ss{_Val - _Dp}); } + template + void _Write_seconds(basic_ostream<_CharT, _Traits>& _Os, const duration<_Rep, _Period>& _Val) { + const auto _Dp = _CHRONO duration_cast(_Val); + _Write_seconds(_Os, hh_mm_ss{_Val - _Dp}); + } + template _NODISCARD tm _Fill_tm(const _Ty& _Val) { unsigned int _Day = 0; @@ -5480,7 +5490,10 @@ namespace chrono { int _Minutes = 0; int _Seconds = 0; - if constexpr (is_same_v<_Ty, day>) { + if constexpr (_Is_specialization_v<_Ty, duration>) { + const auto _Dp = _CHRONO duration_cast(_Val); + return _Fill_tm(hh_mm_ss{_Val - _Dp}); + } else if constexpr (is_same_v<_Ty, day>) { _Day = static_cast(_Val); } else if constexpr (is_same_v<_Ty, month>) { _Month = static_cast(_Val); @@ -5779,7 +5792,9 @@ namespace chrono { template _NODISCARD constexpr bool _Is_valid_type(const char _Type) noexcept { - if constexpr (is_same_v<_Ty, day>) { + if constexpr (_Is_specialization_v<_Ty, duration>) { + return _Type == 'j' || _Type == 'q' || _Type == 'Q' || _Is_valid_type>(_Type); + } else if constexpr (is_same_v<_Ty, day>) { return _Type == 'd' || _Type == 'e'; } else if constexpr (is_same_v<_Ty, month>) { return _Type == 'b' || _Type == 'B' || _Type == 'h' || _Type == 'm'; @@ -5825,6 +5840,10 @@ namespace chrono { if (_Val.is_negative()) { _Stream << _CharT{'-'}; } + } else if constexpr (_Is_specialization_v<_Ty, duration>) { + if (_Val < _Ty::zero()) { + _Stream << _CharT{'-'}; + } } for (const auto& _Spec : _Specs._Chrono_specs_list) { @@ -5892,6 +5911,21 @@ namespace chrono { } _Os << _Time.tm_mday; return true; + case 'j': + if constexpr (_Is_specialization_v<_Ty, duration>) { + _Os << _STD abs(_CHRONO duration_cast(_Val).count()); + } + return true; + case 'q': + if constexpr (_Is_specialization_v<_Ty, duration>) { + _Write_unit_suffix(_Os); + } + return true; + case 'Q': + if constexpr (_Is_specialization_v<_Ty, duration>) { + _Os << _STD abs(_Val.count()); + } + return true; case 'm': if (_Has_modifier) { return false; @@ -5997,6 +6031,10 @@ private: _CHRONO _Chrono_formatter<_CharT> _Impl; }; +template +struct formatter<_CHRONO duration<_Rep, _Period>, _CharT> + : _Fill_tm_formatter<_CHRONO duration<_Rep, _Period>, _CharT> {}; + template struct formatter<_CHRONO day, _CharT> // : _Fill_tm_formatter<_CHRONO day, _CharT> {}; 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 9d6db36597f..311cb96ab79 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 @@ -218,6 +218,27 @@ constexpr void print(Str str) { } } +template +void test_duration_formatter() { + empty_braces_helper(seconds{5}, STR("5s")); + empty_braces_helper(minutes{7}, STR("7min")); + empty_braces_helper(hours{9}, STR("9h")); + empty_braces_helper(days{2}, STR("2d")); + empty_braces_helper(-seconds{5}, STR("-5s")); + empty_braces_helper(duration>{40}, STR("40[3]s")); + empty_braces_helper(duration>{40}, STR("40[3/7]s")); + + assert(format(STR("{:%T}"), 4083007ms) == STR("01:08:03.007")); + assert(format(STR("{:%T}"), -4083007ms) == STR("-01:08:03.007")); + + assert(format(STR("{:%T %j %q %Q}"), days{4} + 30min) == STR("00:30:00 4 min 5790")); + assert(format(STR("{:%T %j %q %Q}"), -days{4} - 30min) == STR("-00:30:00 4 min 5790")); + assert(format(STR("{:%T %j}"), days{4} + 23h + 30min) == STR("23:30:00 4")); + assert(format(STR("{:%T %j}"), -days{4} - 23h - 30min) == STR("-23:30:00 4")); + assert(format(STR("{:%T %j}"), duration{1.55f}) == STR("13:11:59 1")); + assert(format(STR("{:%T %j}"), duration{-1.55f}) == STR("-13:11:59 1")); +} + template void test_clock_formatter() { empty_braces_helper(sys_seconds{}, STR("1970-01-01 00:00:00")); @@ -597,6 +618,9 @@ int main() { test_parse_chrono_format_specs(); test_parse_chrono_format_specs(); + test_duration_formatter(); + test_duration_formatter(); + test_clock_formatter(); test_clock_formatter();