From 38aa6a366847a91a6c638afcd2ff437fd6563316 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 20 Apr 2021 21:01:22 -0700 Subject: [PATCH 1/3] Various cleanups. * Use `else` with `if constexpr` to avoid dead code. * Some helpers can be `static`. * Add a newline between non-chained `if` statements. --- stl/inc/chrono | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 7e49b82e144..a0cf02a6bdc 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -5498,10 +5498,10 @@ namespace chrono { } else { _Write_fractional_seconds<_Fractional_width>(_Os, _Hms.seconds(), _Hms.subseconds()); } - return; + } else { + const auto _Dp = _CHRONO floor(_Val); + _Write_seconds(_Os, hh_mm_ss{_Val - _Dp}); } - const auto _Dp = _CHRONO floor(_Val); - _Write_seconds(_Os, hh_mm_ss{_Val - _Dp}); } template @@ -5848,7 +5848,7 @@ namespace chrono { return _Res_iter; } - void _Check_modifier(const char _Type, const char _Modifier) { + static void _Check_modifier(const char _Type, const char _Modifier) { if (_Modifier == '\0') { return; } @@ -5894,7 +5894,7 @@ namespace chrono { } template - _NODISCARD constexpr bool _Is_valid_type(const char _Type) noexcept { + _NODISCARD static constexpr bool _Is_valid_type(const char _Type) noexcept { 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>) { @@ -6058,6 +6058,7 @@ namespace chrono { _THROW(format_error("The day of year for a month_day_last other than January is ambiguous")); } } + if constexpr (_Has_ok<_Ty>) { if (!_Val.ok()) { _THROW(format_error("Cannot print invalid day of year")); @@ -6187,7 +6188,7 @@ namespace chrono { } } - _NODISCARD array<_CharT, 4> _Fmt_string(const _Chrono_spec<_CharT>& _Spec) { + _NODISCARD static array<_CharT, 4> _Fmt_string(const _Chrono_spec<_CharT>& _Spec) { array<_CharT, 4> _Fmt_str; size_t _Next_idx = 0; _Fmt_str[_Next_idx++] = _CharT{'%'}; From 0d622104da9527b78fa0ca288afc3e13ece5dfc3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 20 Apr 2021 23:58:53 -0700 Subject: [PATCH 2/3] Extend %r to all types (local_time_format, zoned_time). --- stl/inc/chrono | 21 +++++++++---------- .../test.cpp | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index a0cf02a6bdc..7475f63658e 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -6032,18 +6032,17 @@ namespace chrono { _Os << _Time.tm_mday; return true; case 'r': - if constexpr (_Is_specialization_v<_Ty, hh_mm_ss>) { - // put_time uses _Strftime in order to bypass reference-counting that locale uses. This function - // takes the locale information by pointer, but the pointer (from _Gettnames) returns a copy. - // _Strftime delegates to other functions but eventually (for the C locale) has the %r specifier - // rewritten. It checks for the locale by comparing pointers, which do not compare equal as we have - // a copy of the pointer instead of the original. Therefore, we replace %r for the C locale - // ourselves. - if (_Os.getloc() == locale::classic()) { - _Os << _STD put_time(&_Time, _STATICALLY_WIDEN(_CharT, "%I:%M:%S %p")); - return true; - } + // put_time uses _Strftime in order to bypass reference-counting that locale uses. This function + // takes the locale information by pointer, but the pointer (from _Gettnames) returns a copy. + // _Strftime delegates to other functions but eventually (for the C locale) has the %r specifier + // rewritten. It checks for the locale by comparing pointers, which do not compare equal as we have + // a copy of the pointer instead of the original. Therefore, we replace %r for the C locale + // ourselves. + if (_Os.getloc() == locale::classic()) { + _Os << _STD put_time(&_Time, _STATICALLY_WIDEN(_CharT, "%I:%M:%S %p")); + return true; } + return false; case 'j': if constexpr (_Is_specialization_v<_Ty, duration>) { 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 3c14b7c28f5..bf84163f80e 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 @@ -798,7 +798,7 @@ void test_local_time_format_formatter() { assert(format(STR("{:%c, %x, %X}"), ltf) == STR("04/19/21 01:02:03, 04/19/21, 01:02:03")); assert(format(STR("{:%D %F, %Y %C %y, %b %B %h %m, %d %e, %a %A %u %w}"), ltf) == STR("04/19/21 2021-04-19, 2021 20 21, Apr April Apr 04, 19 19, Mon Monday 1 1")); - assert(format(STR("{:%H %I %M %S %r %R %T %p}"), ltf) == STR("01 01 02 03 01:02:03 01:02 01:02:03 AM")); + assert(format(STR("{:%H %I %M %S, %r, %R %T %p}"), ltf) == STR("01 01 02 03, 01:02:03 AM, 01:02 01:02:03 AM")); } template @@ -812,7 +812,7 @@ void test_zoned_time_formatter() { assert(format(STR("{:%c, %x, %X}"), zt) == STR("04/19/21 08:16:17, 04/19/21, 08:16:17")); assert(format(STR("{:%D %F, %Y %C %y, %b %B %h %m, %d %e, %a %A %u %w}"), zt) == STR("04/19/21 2021-04-19, 2021 20 21, Apr April Apr 04, 19 19, Mon Monday 1 1")); - assert(format(STR("{:%H %I %M %S %r %R %T %p}"), zt) == STR("08 08 16 17 08:16:17 08:16 08:16:17 AM")); + assert(format(STR("{:%H %I %M %S, %r, %R %T %p}"), zt) == STR("08 08 16 17, 08:16:17 AM, 08:16 08:16:17 AM")); } int main() { From b834b81c1fd51070e849e3e44a6054e486956a0e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 21 Apr 2021 02:10:47 -0700 Subject: [PATCH 3/3] Implement %g %G %U %V %W. --- stl/inc/chrono | 21 ++++++-- .../test.cpp | 51 +++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 7475f63658e..e8af360e741 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -5910,11 +5910,12 @@ namespace chrono { } else if constexpr (_Is_any_of_v<_Ty, month_weekday, month_weekday_last>) { return _Is_valid_type(_Type) || _Is_valid_type(_Type); } else if constexpr (is_same_v<_Ty, year_month>) { - return _Is_valid_type(_Type) || _Is_valid_type(_Type); + return _Type == 'g' || _Type == 'G' || _Is_valid_type(_Type) || _Is_valid_type(_Type); } else if constexpr (_Is_any_of_v<_Ty, year_month_day, year_month_day_last, year_month_weekday, year_month_weekday_last>) { - return _Type == 'D' || _Type == 'F' || _Type == 'j' || _Is_valid_type(_Type) - || _Is_valid_type(_Type) || _Is_valid_type(_Type) || _Is_valid_type(_Type); + return _Type == 'D' || _Type == 'F' || _Type == 'g' || _Type == 'G' || _Type == 'j' || _Type == 'U' + || _Type == 'V' || _Type == 'W' || _Is_valid_type(_Type) || _Is_valid_type(_Type) + || _Is_valid_type(_Type) || _Is_valid_type(_Type); } else if constexpr (_Is_specialization_v<_Ty, hh_mm_ss>) { return _Type == 'H' || _Type == 'I' || _Type == 'M' || _Type == 'S' || _Type == 'r' || _Type == 'R' || _Type == 'T' || _Type == 'p'; @@ -6031,6 +6032,20 @@ namespace chrono { } _Os << _Time.tm_mday; return true; + case 'g': + case 'G': + if constexpr (is_same_v<_Ty, year_month>) { + if (_Val.month() == January || _Val.month() == December) { + _THROW(format_error( + "The ISO week-based year for a year_month of January or December is ambiguous.")); + } + + const char _Gregorian_type = _Spec._Type == 'g' ? 'y' : 'Y'; + _Os << _STD put_time(&_Time, _Fmt_string({._Type = _Gregorian_type}).data()); + return true; + } + + return false; case 'r': // put_time uses _Strftime in order to bypass reference-counting that locale uses. This function // takes the locale information by pointer, but the pointer (from _Gettnames) returns a copy. 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 bf84163f80e..6fd4b2117b9 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 @@ -249,6 +249,24 @@ void test_clock_formatter() { assert(format(STR("{:%Z %z %Oz %Ez}"), file_time{}) == STR("UTC +0000 +00:00 +00:00")); throw_helper(STR("{:%Z %z %Oz %Ez}"), local_seconds{}); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / January / 1}) == STR("09 2009 00 53 00")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / January / 2}) == STR("09 2009 00 53 00")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / January / 3}) == STR("09 2009 01 53 00")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / January / 4}) == STR("10 2010 01 01 01")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / January / 5}) == STR("10 2010 01 01 01")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / January / 6}) == STR("10 2010 01 01 01")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / January / 7}) == STR("10 2010 01 01 01")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / May / 1}) == STR("10 2010 17 17 17")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / May / 2}) == STR("10 2010 18 17 17")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / May / 3}) == STR("10 2010 18 18 18")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / December / 25}) == STR("10 2010 51 51 51")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / December / 26}) == STR("10 2010 52 51 51")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / December / 27}) == STR("10 2010 52 52 52")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / December / 28}) == STR("10 2010 52 52 52")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / December / 29}) == STR("10 2010 52 52 52")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / December / 30}) == STR("10 2010 52 52 52")); + assert(format(STR("{:%g %G %U %V %W}"), sys_days{2010y / December / 31}) == STR("10 2010 52 52 52")); + 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")); @@ -515,6 +533,13 @@ void test_year_month_formatter() { assert(format(STR("{:%Y %B}"), 2000y / July) == STR("2000 July")); throw_helper(STR("{:%d}"), 2000y / July); + + throw_helper(STR("{:%g}"), 2005y / January); + throw_helper(STR("{:%G}"), 2005y / January); + assert(format(STR("{:%g %G}"), 2005y / February) == STR("05 2005")); + assert(format(STR("{:%g %G}"), 2005y / November) == STR("05 2005")); + throw_helper(STR("{:%g}"), 2005y / December); + throw_helper(STR("{:%G}"), 2005y / December); } template @@ -533,6 +558,24 @@ void test_year_month_day_formatter() { assert(format(STR("{:%j}"), 1900y / May / 7) == STR("127")); assert(format(STR("{:%j}"), 2000y / May / 7) == STR("128")); throw_helper(STR("{:%j}"), invalid); + + assert(format(STR("{:%g %G %U %V %W}"), 2010y / January / 1) == STR("09 2009 00 53 00")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / January / 2) == STR("09 2009 00 53 00")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / January / 3) == STR("09 2009 01 53 00")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / January / 4) == STR("10 2010 01 01 01")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / January / 5) == STR("10 2010 01 01 01")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / January / 6) == STR("10 2010 01 01 01")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / January / 7) == STR("10 2010 01 01 01")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / May / 1) == STR("10 2010 17 17 17")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / May / 2) == STR("10 2010 18 17 17")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / May / 3) == STR("10 2010 18 18 18")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / December / 25) == STR("10 2010 51 51 51")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / December / 26) == STR("10 2010 52 51 51")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / December / 27) == STR("10 2010 52 52 52")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / December / 28) == STR("10 2010 52 52 52")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / December / 29) == STR("10 2010 52 52 52")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / December / 30) == STR("10 2010 52 52 52")); + assert(format(STR("{:%g %G %U %V %W}"), 2010y / December / 31) == STR("10 2010 52 52 52")); } template @@ -557,6 +600,8 @@ void test_year_month_day_last_formatter() { assert(format(STR("{:%j}"), 1900y / February / last) == STR("059")); assert(format(STR("{:%j}"), 2000y / February / last) == STR("060")); throw_helper(STR("{:%j}"), year{1900} / month{13} / last); + + assert(format(STR("{:%g %G %U %V %W}"), 2010y / May / last) == STR("10 2010 22 22 22")); } template @@ -586,6 +631,8 @@ void test_year_month_weekday_formatter() { assert(format(STR("{:%j}"), 1900y / January / Tuesday[2]) == STR("009")); throw_helper(STR("{:%j}"), invalid1); + + assert(format(STR("{:%g %G %U %V %W}"), 2010y / May / Monday[5]) == STR("10 2010 22 22 22")); } template @@ -613,6 +660,8 @@ void test_year_month_weekday_last_formatter() { assert(format(STR("{:%j}"), 1900y / January / Tuesday[last]) == STR("030")); throw_helper(STR("{:%j}"), invalid1); + + assert(format(STR("{:%g %G %U %V %W}"), 2010y / May / Monday[last]) == STR("10 2010 22 22 22")); } template @@ -799,6 +848,7 @@ void test_local_time_format_formatter() { assert(format(STR("{:%D %F, %Y %C %y, %b %B %h %m, %d %e, %a %A %u %w}"), ltf) == STR("04/19/21 2021-04-19, 2021 20 21, Apr April Apr 04, 19 19, Mon Monday 1 1")); assert(format(STR("{:%H %I %M %S, %r, %R %T %p}"), ltf) == STR("01 01 02 03, 01:02:03 AM, 01:02 01:02:03 AM")); + assert(format(STR("{:%g %G %U %V %W}"), ltf) == STR("21 2021 16 16 16")); } template @@ -813,6 +863,7 @@ void test_zoned_time_formatter() { assert(format(STR("{:%D %F, %Y %C %y, %b %B %h %m, %d %e, %a %A %u %w}"), zt) == STR("04/19/21 2021-04-19, 2021 20 21, Apr April Apr 04, 19 19, Mon Monday 1 1")); assert(format(STR("{:%H %I %M %S, %r, %R %T %p}"), zt) == STR("08 08 16 17, 08:16:17 AM, 08:16 08:16:17 AM")); + assert(format(STR("{:%g %G %U %V %W}"), zt) == STR("21 2021 16 16 16")); } int main() {