On Mon, Jun 2, 2025 at 1:21 PM Tomasz Kamiński <tkami...@redhat.com> wrote:
> This patch fixes the handle multiple digits values for the month, day, > weekday > and hour, when used with the %m, %d, %e, %m, %u, %w, %H, and %D, %F > specifiers. > The values are now printed unmodified. This patch also fixes printing > negative > year with %F, where the values was not padded to four digits. > > Furthemore, the %I,%p are adjusted to handle input with hours values set to > over 24 hours. In the case the values is interpretd modulo 24. This was > already > the case for %r (locale's 12-hour clock), as we convert the input into > seconds. > > In case of %u, %w we print values unchanged, this makes the behavior of > this > specifiers equivalent to printing the iso_encoding and c_encoding > respectively. > As constructing weekday from value 7, initializes it with 0, the !ok() > weekdays > values are always greater of equal eight, so they are clearly > distinguishable. > > The months, weekday, day values that can have 3 decimal digit as maximum > (range [0, 255]), we are using new _S_str_d1, _S_str_d2 that return > string_view > containing textual representation, without padding or padded to two digits. > This function accepts are 3 character buffer, that are used for 3 digits > number. > In other cases, we return _S_digit and _S_two_digits result directly. The > former > is changed to return string_view to facilitate this. > > For %F and %D when at least one component have more digits that expected > (2 for > month and day, 4 for year), we produce output using format_to with > appropriate > format string. Otherwise the representation is produced in local char > buffer. > Two simply fill this buffer, _S_fill_two_digits function was added. We also > make sure that minus is not included in year width for %F. > > The handling of %C, %Y, %y was adjusted to use similar pattern, for years > with > more than two digits. To support that the order of characters in _S_chars > was > adjusted so it contain "-{}" string. > > For handling of %H, we print 3 or more digits values using format_to. The > handling > for large hours values in %T and %R was changed, so they printed using > format_to, > and otherwise we use same stack buffer as for minutes to print them. > > PR libstdc++/120481 > > libstdc++-v3/ChangeLog: > > * include/bits/chrono_io.h (__format::_S_chars): Reorder so it > contains "-{}". > (__format::_S_colon, __format::_S_slash, __format::_S_space) > (__format::_S_plus_minus): Updated starting indicies. > (__format::_S_minus_empty_spec): Define. > (__formatter_chrono::_M_C_y_Y, __formatter_chrono::_M_R_T): > Rework implementation. > (__formatter_chrono::_M_d_e, __formatter_chrono::_M_F) > (__formatter_chrono::_M_m, __formatter_chrono::_M_u_w) > (__formatter_chrono::_M_H_I, __formatter_chrono::_M_p): > Handle multi digits values. > (__formatter_chrono::_S_digit): Return string view. > (__formatter_chrono::_S_str_d1, __formatter_chrono::_S_str_d2) > (__formatter_chrono::_S_fill_two_digits): Define. > * testsuite/std/time/format/empty_spec.cc: Update test for > year_month_day, that uses '%F'. > * testsuite/std/time/format/pr120481.cc: New test. > --- > Tested on x86_64 linux. OK for trunk? > > libstdc++-v3/include/bits/chrono_io.h | 219 ++++++++---- > .../testsuite/std/time/format/empty_spec.cc | 12 +- > .../testsuite/std/time/format/pr120481.cc | 324 ++++++++++++++++++ > 3 files changed, 481 insertions(+), 74 deletions(-) > create mode 100644 libstdc++-v3/testsuite/std/time/format/pr120481.cc > > diff --git a/libstdc++-v3/include/bits/chrono_io.h > b/libstdc++-v3/include/bits/chrono_io.h > index 346eb8b3c33..5afef783ae9 100644 > --- a/libstdc++-v3/include/bits/chrono_io.h > +++ b/libstdc++-v3/include/bits/chrono_io.h > @@ -785,11 +785,12 @@ namespace __format > } > > static constexpr const _CharT* _S_chars > - = _GLIBCXX_WIDEN("0123456789+-:/ {}"); > - static constexpr const _CharT* _S_plus_minus = _S_chars + 10; > - static constexpr _CharT _S_colon = _S_chars[12]; > - static constexpr _CharT _S_slash = _S_chars[13]; > - static constexpr _CharT _S_space = _S_chars[14]; > + = _GLIBCXX_WIDEN("0123456789:/ +-{}"); > + static constexpr _CharT _S_colon = _S_chars[10]; > + static constexpr _CharT _S_slash = _S_chars[11]; > + static constexpr _CharT _S_space = _S_chars[12]; > + static constexpr const _CharT* _S_plus_minus = _S_chars + 13; > + static constexpr const _CharT* _S_minus_empty_spec = _S_chars + 14; > static constexpr const _CharT* _S_empty_spec = _S_chars + 15; > > template<typename _OutIter> > @@ -941,33 +942,39 @@ namespace __format > __conv, __mod); > } > > - basic_string<_CharT> __s; > int __yi = (int)__y; > const bool __is_neg = __yi < 0; > __yi = __builtin_abs(__yi); > + int __ci = __yi / 100; > + // For floored division -123//100 is -2 and -100//100 is -1 > + if (__conv == 'C' && __is_neg && (__ci * 100) != __yi) > [[unlikely]] > + ++__ci; > > - if (__conv == 'Y' || __conv == 'C') > + if (__conv != 'y' && __ci >= 100) [[unlikely]] > { > - int __ci = __yi / 100; > - if (__is_neg) [[unlikely]] > + using _FmtStr = _Runtime_format_string<_CharT>; > + __string_view __fs = _S_minus_empty_spec + !__is_neg; > + __out = std::format_to(std::move(__out), _FmtStr(__fs), > + __conv == 'C' ? __ci : __yi); > + } > + else > + { > + _CharT __buf[5]; > + __buf[0] = _S_plus_minus[1]; > + __string_view __sv(__buf + 3, __buf + 3); > + if (__conv != 'y') > { > - __s.assign(1, _S_plus_minus[1]); > - // For floored division -123//100 is -2 and -100//100 is > -1 > - if (__conv == 'C' && (__ci * 100) != __yi) > - ++__ci; > + _S_fill_two_digits(__buf + 1, __ci); > + __sv = __string_view(__buf + !__is_neg, __buf + 3); > } > - if (__ci >= 100) [[unlikely]] > + if (__conv != 'C') > { > - __s += std::format(_S_empty_spec, __ci / 100); > - __ci %= 100; > + _S_fill_two_digits(__buf + 3, __yi % 100); > + __sv = __string_view(__sv.data(), __buf + 5); > } > - __s += _S_two_digits(__ci); > + __out = __format::__write(std::move(__out), __sv); > } > - > - if (__conv == 'Y' || __conv == 'y') > - __s += _S_two_digits(__yi % 100); > - > - return __format::__write(std::move(__out), __string_view(__s)); > + return std::move(__out); > } > > template<typename _Tp, typename _FormatContext> > @@ -976,16 +983,30 @@ namespace __format > _FormatContext&) const > { > auto __ymd = _S_date(__t); > - basic_string<_CharT> __s; > -#if ! _GLIBCXX_USE_CXX11_ABI > - __s.reserve(8); > -#endif > - __s = _S_two_digits((unsigned)__ymd.month()); > - __s += _S_slash; > - __s += _S_two_digits((unsigned)__ymd.day()); > - __s += _S_slash; > - __s += _S_two_digits(__builtin_abs((int)__ymd.year()) % 100); > - return __format::__write(std::move(__out), __string_view(__s)); > + auto __di = (unsigned)__ymd.day(); > + auto __mi = (unsigned)__ymd.month(); > + auto __yi = __builtin_abs((int)__ymd.year()) % 100; > + > + if (__mi >= 100 || __di >= 100) [[unlikely]] > + { > + using _FmtStr = _Runtime_format_string<_CharT>; > + __string_view __fs = _GLIBCXX_WIDEN("{:02d}/{:02d}/{:02d}"); > + __out = std::format_to(std::move(__out), _FmtStr(__fs), > + __mi, __di, __yi); > + } > + else > + { > + _CharT __buf[8]; > + __buf[2] = _S_slash; > + __buf[5] = _S_slash; > + __string_view __sv(__buf, __buf + 8); > + > + _S_fill_two_digits(__buf, __mi); > + _S_fill_two_digits(__buf + 3, __di); > + _S_fill_two_digits(__buf + 6, __yi); > + __out = __format::__write(std::move(__out), __sv); > + } > + return std::move(__out); > } > > template<typename _Tp, typename _FormatContext> > @@ -1010,12 +1031,12 @@ namespace __format > (char)__conv, 'O'); > } > > - auto __sv = _S_two_digits(__i); > - _CharT __buf[2]; > + _CharT __buf[3]; > + auto __sv = _S_str_d2(__buf, __i); > if (__conv == _CharT('e') && __i < 10) > { > - __buf[0] = _S_space; > __buf[1] = __sv[1]; > + __buf[0] = _S_space; > I have documented that _S_str_d2(__buf, __i) may refer to __buf. It does not for single character result, but changed to order here, so we firstly read the digit from __sv, before overriding any part of __sv. This will work, regardless if and which part of __buf will be aliased by __sv. > __sv = {__buf, 2}; > } > return __format::__write(std::move(__out), __sv); > @@ -1027,16 +1048,35 @@ namespace __format > _FormatContext&) const > { > auto __ymd = _S_date(__t); > - auto __s = std::format(_GLIBCXX_WIDEN("{:04d}- - "), > - (int)__ymd.year()); > - auto __sv = _S_two_digits((unsigned)__ymd.month()); > - __s[__s.size() - 5] = __sv[0]; > - __s[__s.size() - 4] = __sv[1]; > - __sv = _S_two_digits((unsigned)__ymd.day()); > - __s[__s.size() - 2] = __sv[0]; > - __s[__s.size() - 1] = __sv[1]; > - __sv = __s; > - return __format::__write(std::move(__out), __sv); > + auto __di = (unsigned)__ymd.day(); > + auto __mi = (unsigned)__ymd.month(); > + auto __yi = (int)__ymd.year(); > + const bool __is_neg = __yi < 0; > + __yi = __builtin_abs(__yi); > + > + if (__yi >= 10000 || __mi >= 100 || __di >= 100) [[unlikely]] > + { > + using _FmtStr = _Runtime_format_string<_CharT>; > + __string_view __fs > + = _GLIBCXX_WIDEN("-{:04d}-{:02d}-{:02d}") + !__is_neg; > + __out = std::format_to(std::move(__out), _FmtStr(__fs), > + __yi, __mi, __di); > + } > + else > + { > + _CharT __buf[11]; > + __buf[0] = _S_plus_minus[1]; > + __buf[5] = _S_plus_minus[1]; > + __buf[8] = _S_plus_minus[1]; > + __string_view __sv(__buf + !__is_neg, __buf + 11); > + > + _S_fill_two_digits(__buf + 1, __yi / 100); > + _S_fill_two_digits(__buf + 3, __yi % 100); > + _S_fill_two_digits(__buf + 6, __mi); > + _S_fill_two_digits(__buf + 9, __di); > + __out = __format::__write(std::move(__out), __sv); > + } > + return std::move(__out); > } > > template<typename _Tp, typename _FormatContext> > @@ -1079,11 +1119,13 @@ namespace __format > > if (__conv == _CharT('I')) > { > + __i %= 12; > if (__i == 0) > __i = 12; > - else if (__i > 12) > - __i -= 12; > } > + else if (__i >= 100) [[unlikely]] > + return std::format_to(std::move(__out), _S_empty_spec, __i); > + > return __format::__write(std::move(__out), _S_two_digits(__i)); > } > > @@ -1136,7 +1178,8 @@ namespace __format > 'm', 'O'); > } > > - return __format::__write(std::move(__out), _S_two_digits(__i)); > + _CharT __buf[3]; > + return __format::__write(std::move(__out), _S_str_d2(__buf, > __i)); > } > > template<typename _Tp, typename _FormatContext> > @@ -1169,12 +1212,15 @@ namespace __format > { > // %p The locale's equivalent of the AM/PM designations. > auto __hms = _S_hms(__t); > + auto __hi = __hms.hours().count(); > + if (__hi >= 24) [[unlikely]] > + __hi %= 24; > + > locale __loc = _M_locale(__ctx); > const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); > const _CharT* __ampm[2]; > __tp._M_am_pm(__ampm); > - return _M_write(std::move(__out), __loc, > - __ampm[__hms.hours().count() >= 12]); > + return _M_write(std::move(__out), __loc, __ampm[__hi >= 12]); > } > > template<typename _Tp, typename _FormatContext> > @@ -1222,19 +1268,25 @@ namespace __format > // %R Equivalent to %H:%M > // %T Equivalent to %H:%M:%S > auto __hms = _S_hms(__t); > + auto __hi = __hms.hours().count(); > > - auto __s = std::format(_GLIBCXX_WIDEN("{:02d}:00"), > - __hms.hours().count()); > - auto __sv = _S_two_digits(__hms.minutes().count()); > - __s[__s.size() - 2] = __sv[0]; > - __s[__s.size() - 1] = __sv[1]; > - __sv = __s; > - __out = __format::__write(std::move(__out), __sv); > - if (__secs) > + _CharT __buf[6]; > + __buf[2] = _S_colon; > + __buf[5] = _S_colon; > + __string_view __sv(__buf, 5 + __secs); > + > + if (__hi >= 100) [[unlikely]] > { > - *__out++ = _S_colon; > - __out = _M_S(__hms, std::move(__out), __ctx); > + __out = std::format_to(std::move(__out), _S_empty_spec, > __hi); > + __sv.remove_prefix(2); > } > + else > + _S_fill_two_digits(__buf, __hi); > + > + _S_fill_two_digits(__buf + 3, __hms.minutes().count()); > + __out = __format::__write(std::move(__out), __sv); > + if (__secs) > + __out = _M_S(__hms, std::move(__out), __ctx); > return __out; > } > > @@ -1330,8 +1382,8 @@ namespace __format > > unsigned __wdi = __conv == 'u' ? __wd.iso_encoding() > : __wd.c_encoding(); > - const _CharT __d = _S_digit(__wdi); > - return __format::__write(std::move(__out), __string_view(&__d, > 1)); > + _CharT __buf[3]; > + return __format::__write(std::move(__out), _S_str_d1(__buf, > __wdi)); > } > > template<typename _Tp, typename _FormatContext> > @@ -1516,12 +1568,12 @@ namespace __format > > // %% handled in _M_format > > - // A single digit character in the range '0'..'9'. > - static _CharT > + // A string view of single digit character, "0".."9". > + static basic_string_view<_CharT> > _S_digit(int __n) noexcept > { > // Extra 9s avoid past-the-end read on bad input. > - return _GLIBCXX_WIDEN("0123456789999999")[__n & 0xf]; > + return { _GLIBCXX_WIDEN("0123456789999999") + (__n & 0xf), 1 }; > } > > // A string view of two digit characters, "00".."99". > @@ -1540,7 +1592,42 @@ namespace __format > }; > } > > - // Accessors for the components of chrono types: > + [[__gnu__::__always_inline__]] > + // Fills __buf[0] and __buf[1] with 2 digit value of __n. > + static void > + _S_fill_two_digits(_CharT* __buf, unsigned __n) > + { > + auto __sv = _S_two_digits(__n); > + __buf[0] = __sv[0]; > + __buf[1] = __sv[1]; > + } > + > + // Returns decimal represenation of __n. > + // Returned string_view may point to __buf. > + [[__gnu__::__always_inline__]] > + static basic_string_view<_CharT> > + _S_str_d1(span<_CharT, 3> __buf, unsigned __n) > + { > + if (__n < 10) [[likely]] > + return _S_digit(__n); > + return _S_str_d2(__buf, __n); > + } > + > + // Returns decimal represenation of __n, padded to 2 digits. > + // Returned string_view may point to __buf. > + [[__gnu__::__always_inline__]] > + static basic_string_view<_CharT> > + _S_str_d2(span<_CharT, 3> __buf, unsigned __n) > + { > + if (__n < 100) [[likely]] > + return _S_two_digits(__n); > + > + _S_fill_two_digits(__buf.data(), __n / 10); > + __buf[2] = _S_digit(__n % 10)[0]; > + return __string_view(__buf.data(), 3); > + } > + > + // Accessors for the components of chrono types: > > // Returns a hh_mm_ss. > template<typename _Tp> > diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc > b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc > index 322faa1939d..095c0e1121a 100644 > --- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc > +++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc > @@ -196,19 +196,15 @@ test_year_month_day() > verify( year(2024)/month(1)/30, > WIDEN("2024-01-30") ); > verify( year(-100)/month(14)/1, > - // Should be -0100-14-01 > - WIDEN("-100-14-01 is not a valid date") ); > + WIDEN("-0100-14-01 is not a valid date") ); > verify( year(2025)/month(11)/100, > - // Should be 2025-11-100 ? > - WIDEN("2025-11-99 is not a valid date") ); > + WIDEN("2025-11-100 is not a valid date") ); > verify( year(-32768)/month(2)/10, > WIDEN("-32768-02-10 is not a valid date") ); > verify( year(-32768)/month(212)/10, > - // Should be 32768-212-10? > - WIDEN("-32768-84-10 is not a valid date") ); > + WIDEN("-32768-212-10 is not a valid date") ); > verify( year(-32768)/month(2)/105, > - // Should be 32768-02-99? > - WIDEN("-32768-02-99 is not a valid date") ); > + WIDEN("-32768-02-105 is not a valid date") ); > verify( year(-32768)/month(14)/55, > WIDEN("-32768-14-55 is not a valid date") ); > } > diff --git a/libstdc++-v3/testsuite/std/time/format/pr120481.cc > b/libstdc++-v3/testsuite/std/time/format/pr120481.cc > new file mode 100644 > index 00000000000..5878c5ba397 > --- /dev/null > +++ b/libstdc++-v3/testsuite/std/time/format/pr120481.cc > @@ -0,0 +1,324 @@ > +// { dg-do run { target c++23 } } > +// { dg-options "-fexec-charset=UTF-8" } > +// { dg-timeout-factor 2 } > + > +#include <algorithm> > +#include <chrono> > +#include <testsuite_hooks.h> > + > +#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) > +#define WIDEN(S) WIDEN_(_CharT, S) > + > +using namespace std::chrono; > + > +template<typename _CharT> > +void > +test_year() > +{ > + std::basic_string<_CharT> res; > + > + res = std::format(WIDEN("{:%Y}"), year(0)); > + VERIFY( res == WIDEN("0000") ); > + res = std::format(WIDEN("{:%C}"), year(0)); > + VERIFY( res == WIDEN("00") ); > + res = std::format(WIDEN("{:%y}"), year(0)); > + VERIFY( res == WIDEN("00") ); > + > + res = std::format(WIDEN("{:%Y}"), year(5)); > + VERIFY( res == WIDEN("0005") ); > + res = std::format(WIDEN("{:%C}"), year(5)); > + VERIFY( res == WIDEN("00") ); > + res = std::format(WIDEN("{:%y}"), year(5)); > + VERIFY( res == WIDEN("05") ); > + res = std::format(WIDEN("{:%Y}"), year(-5)); > + VERIFY( res == WIDEN("-0005") ); > + res = std::format(WIDEN("{:%C}"), year(-5)); > + VERIFY( res == WIDEN("-01") ); > + res = std::format(WIDEN("{:%y}"), year(-5)); > + VERIFY( res == WIDEN("05") ); > + > + res = std::format(WIDEN("{:%Y}"), year(213)); > + VERIFY( res == WIDEN("0213") ); > + res = std::format(WIDEN("{:%C}"), year(213)); > + VERIFY( res == WIDEN("02") ); > + res = std::format(WIDEN("{:%y}"), year(213)); > + VERIFY( res == WIDEN("13") ); > + res = std::format(WIDEN("{:%Y}"), year(-213)); > + VERIFY( res == WIDEN("-0213") ); > + res = std::format(WIDEN("{:%C}"), year(-213)); > + VERIFY( res == WIDEN("-03") ); > + res = std::format(WIDEN("{:%y}"), year(-213)); > + VERIFY( res == WIDEN("13") ); > + > + res = std::format(WIDEN("{:%Y}"), year(7100)); > + VERIFY( res == WIDEN("7100") ); > + res = std::format(WIDEN("{:%C}"), year(7100)); > + VERIFY( res == WIDEN("71") ); > + res = std::format(WIDEN("{:%y}"), year(7100)); > + VERIFY( res == WIDEN("00") ); > + res = std::format(WIDEN("{:%Y}"), year(-7100)); > + VERIFY( res == WIDEN("-7100") ); > + res = std::format(WIDEN("{:%C}"), year(-7100)); > + VERIFY( res == WIDEN("-71") ); > + res = std::format(WIDEN("{:%y}"), year(-7100)); > + VERIFY( res == WIDEN("00") ); > + > + res = std::format(WIDEN("{:%Y}"), year(12101)); > + VERIFY( res == WIDEN("12101") ); > + res = std::format(WIDEN("{:%C}"), year(12101)); > + VERIFY( res == WIDEN("121") ); > + res = std::format(WIDEN("{:%y}"), year(12101)); > + VERIFY( res == WIDEN("01") ); > + res = std::format(WIDEN("{:%Y}"), year(-12101)); > + VERIFY( res == WIDEN("-12101") ); > + res = std::format(WIDEN("{:%C}"), year(-12101)); > + VERIFY( res == WIDEN("-122") ); > + res = std::format(WIDEN("{:%y}"), year(-12101)); > + VERIFY( res == WIDEN("01") ); > +} > + > +template<typename _CharT> > +void > +test_month() > +{ > + std::basic_string<_CharT> res; > + > + res = std::format(WIDEN("{:%m}"), month(5)); > + VERIFY( res == WIDEN("05") ); > + res = std::format(WIDEN("{:%m}"), month(50)); > + VERIFY( res == WIDEN("50") ); > + res = std::format(WIDEN("{:%m}"), month(127)); > + VERIFY( res == WIDEN("127") ); > + res = std::format(WIDEN("{:%m}"), month(254)); > + VERIFY( res == WIDEN("254") ); > +} > + > +template<typename _CharT> > +void > +test_day() > +{ > + std::basic_string<_CharT> res; > + > + res = std::format(WIDEN("{:%d}"), day(3)); > + VERIFY( res == WIDEN("03") ); > + res = std::format(WIDEN("{:%d}"), day(22)); > + VERIFY( res == WIDEN("22") ); > + res = std::format(WIDEN("{:%d}"), day(100)); > + VERIFY( res == WIDEN("100") ); > + res = std::format(WIDEN("{:%d}"), day(207)); > + VERIFY( res == WIDEN("207") ); > + > + res = std::format(WIDEN("{:%e}"), day(5)); > + VERIFY( res == WIDEN(" 5") ); > + res = std::format(WIDEN("{:%e}"), day(99)); > + VERIFY( res == WIDEN("99") ); > + res = std::format(WIDEN("{:%e}"), day(183)); > + VERIFY( res == WIDEN("183") ); > + res = std::format(WIDEN("{:%e}"), day(214)); > + VERIFY( res == WIDEN("214") ); > +} > + > +template<typename _CharT> > +void > +test_date() > +{ > + std::basic_string<_CharT> res; > + > + res = std::format(WIDEN("{:%F}"), year(-22)/month(10)/day(20)); > + VERIFY( res == WIDEN("-0022-10-20") ); > + res = std::format(WIDEN("{:%D}"), year(-22)/month(10)/day(20)); > + VERIFY( res == WIDEN("10/20/22") ); > + > + res = std::format(WIDEN("{:%F}"), year(-2020)/month(123)/day(44)); > + VERIFY( res == WIDEN("-2020-123-44") ); > + res = std::format(WIDEN("{:%D}"), year(-2020)/month(123)/day(44)); > + VERIFY( res == WIDEN("123/44/20") ); > + > + res = std::format(WIDEN("{:%F}"), year(-23404)/month(99)/day(223)); > + VERIFY( res == WIDEN("-23404-99-223") ); > + res = std::format(WIDEN("{:%D}"), year(-23404)/month(99)/day(223)); > + VERIFY( res == WIDEN("99/223/04") ); > + > + res = std::format(WIDEN("{:%F}"), year(10000)/month(220)/day(100)); > + VERIFY( res == WIDEN("10000-220-100") ); > + res = std::format(WIDEN("{:%D}"), year(10000)/month(220)/day(100)); > + VERIFY( res == WIDEN("220/100/00") ); > +} > + > +template<typename _CharT> > +void > +test_weekday() > +{ > + std::basic_string<_CharT> res; > + > + res = std::format(WIDEN("{:%w}"), weekday(0)); > + VERIFY( res == WIDEN("0") ); > + res = std::format(WIDEN("{:%u}"), weekday(0)); > + VERIFY( res == WIDEN("7") ); > + > + res = std::format(WIDEN("{:%w}"), weekday(7)); > + VERIFY( res == WIDEN("0") ); > + res = std::format(WIDEN("{:%u}"), weekday(7)); > + VERIFY( res == WIDEN("7") ); > + > + res = std::format(WIDEN("{:%w}"), weekday(8)); > + VERIFY( res == WIDEN("8") ); > + res = std::format(WIDEN("{:%u}"), weekday(8)); > + VERIFY( res == WIDEN("8") ); > + > + res = std::format(WIDEN("{:%w}"), weekday(10)); > + VERIFY( res == WIDEN("10") ); > + res = std::format(WIDEN("{:%u}"), weekday(10)); > + VERIFY( res == WIDEN("10") ); > + > + res = std::format(WIDEN("{:%w}"), weekday(76)); > + VERIFY( res == WIDEN("76") ); > + res = std::format(WIDEN("{:%u}"), weekday(76)); > + VERIFY( res == WIDEN("76") ); > + > + res = std::format(WIDEN("{:%w}"), weekday(100)); > + VERIFY( res == WIDEN("100") ); > + res = std::format(WIDEN("{:%u}"), weekday(100)); > + VERIFY( res == WIDEN("100") ); > + > + res = std::format(WIDEN("{:%w}"), weekday(202)); > + VERIFY( res == WIDEN("202") ); > + res = std::format(WIDEN("{:%u}"), weekday(202)); > + VERIFY( res == WIDEN("202") ); > +} > + > +template<typename _CharT> > +void > +test_hour() > +{ > + std::basic_string<_CharT> res; > + > + res = std::format(WIDEN("{:%H}"), 0h + 5min + 6s); > + VERIFY( res == WIDEN("00") ); > + res = std::format(WIDEN("{:%R}"), 0h + 5min + 6s); > + VERIFY( res == WIDEN("00:05") ); > + res = std::format(WIDEN("{:%T}"), 0h + 5min + 6s); > + VERIFY( res == WIDEN("00:05:06") ); > + res = std::format(WIDEN("{:%I}"), 0h + 5min + 6s); > + VERIFY( res == WIDEN("12") ); > + res = std::format(WIDEN("{:%p}"), 0h + 5min + 6s); > + VERIFY( res == WIDEN("AM") ); > + > + res = std::format(WIDEN("{:%H}"), 7h + 15min + 6s); > + VERIFY( res == WIDEN("07") ); > + res = std::format(WIDEN("{:%R}"), 7h + 15min + 6s); > + VERIFY( res == WIDEN("07:15") ); > + res = std::format(WIDEN("{:%T}"), 7h + 15min + 6s); > + VERIFY( res == WIDEN("07:15:06") ); > + res = std::format(WIDEN("{:%I}"), 7h + 15min + 6s); > + VERIFY( res == WIDEN("07") ); > + res = std::format(WIDEN("{:%p}"), 7h + 15min + 6s); > + VERIFY( res == WIDEN("AM") ); > + > + res = std::format(WIDEN("{:%H}"), 15h + 55min + 26s); > + VERIFY( res == WIDEN("15") ); > + res = std::format(WIDEN("{:%R}"), 15h + 55min + 26s); > + VERIFY( res == WIDEN("15:55") ); > + res = std::format(WIDEN("{:%T}"), 15h + 55min + 26s); > + VERIFY( res == WIDEN("15:55:26") ); > + res = std::format(WIDEN("{:%I}"), 15h + 55min + 26s); > + VERIFY( res == WIDEN("03") ); > + res = std::format(WIDEN("{:%p}"), 15h + 55min + 26s); > + VERIFY( res == WIDEN("PM") ); > + > + res = std::format(WIDEN("{:%H}"), 50h + 33min + 37s); > + VERIFY( res == WIDEN("50") ); > + res = std::format(WIDEN("{:%R}"), 50h + 33min + 37s); > + VERIFY( res == WIDEN("50:33") ); > + res = std::format(WIDEN("{:%T}"), 50h + 33min + 37s); > + VERIFY( res == WIDEN("50:33:37") ); > + res = std::format(WIDEN("{:%I}"), 50h + 33min + 37s); > + VERIFY( res == WIDEN("02") ); > + res = std::format(WIDEN("{:%p}"), 50h + 33min + 37s); > + VERIFY( res == WIDEN("AM") ); > + > + res = std::format(WIDEN("{:%H}"), 100h + 21min + 48s); > + VERIFY( res == WIDEN("100") ); > + res = std::format(WIDEN("{:%R}"), 100h + 21min + 48s); > + VERIFY( res == WIDEN("100:21") ); > + res = std::format(WIDEN("{:%T}"), 100h + 21min + 48s); > + VERIFY( res == WIDEN("100:21:48") ); > + res = std::format(WIDEN("{:%I}"), 100h + 21min + 48s); > + VERIFY( res == WIDEN("04") ); > + res = std::format(WIDEN("{:%p}"), 100h + 21min + 48s); > + VERIFY( res == WIDEN("AM") ); > + > + res = std::format(WIDEN("{:%H}"), 228h + 45min + 33s); > + VERIFY( res == WIDEN("228") ); > + res = std::format(WIDEN("{:%R}"), 228h + 45min + 33s); > + VERIFY( res == WIDEN("228:45") ); > + res = std::format(WIDEN("{:%T}"), 228h + 45min + 33s); > + VERIFY( res == WIDEN("228:45:33") ); > + res = std::format(WIDEN("{:%I}"), 228h + 4min + 33s); > + VERIFY( res == WIDEN("12") ); > + res = std::format(WIDEN("{:%p}"), 228h + 4min + 33s); > + VERIFY( res == WIDEN("PM") ); > + > + res = std::format(WIDEN("{:%H}"), 1024h + 3min); > + VERIFY( res == WIDEN("1024") ); > + res = std::format(WIDEN("{:%R}"), 1024h + 3min); > + VERIFY( res == WIDEN("1024:03") ); > + res = std::format(WIDEN("{:%T}"), 1024h + 3min); > + VERIFY( res == WIDEN("1024:03:00") ); > + res = std::format(WIDEN("{:%I}"), 1024h + 3min); > + VERIFY( res == WIDEN("04") ); > + res = std::format(WIDEN("{:%p}"), 1024h + 3min); > + VERIFY( res == WIDEN("PM") ); > + > + res = std::format(WIDEN("{:%H}"), 2039h); > + VERIFY( res == WIDEN("2039") ); > + res = std::format(WIDEN("{:%R}"), 2039h); > + VERIFY( res == WIDEN("2039:00") ); > + res = std::format(WIDEN("{:%T}"), 2039h); > + VERIFY( res == WIDEN("2039:00:00") ); > + res = std::format(WIDEN("{:%I}"), 2039h); > + VERIFY( res == WIDEN("11") ); > + res = std::format(WIDEN("{:%p}"), 2039h); > + VERIFY( res == WIDEN("PM") ); > + > + res = std::format(WIDEN("{:%H}"), 22111h + 59min + 59s); > + VERIFY( res == WIDEN("22111") ); > + res = std::format(WIDEN("{:%R}"), 22111h + 59min + 59s); > + VERIFY( res == WIDEN("22111:59") ); > + res = std::format(WIDEN("{:%T}"), 22111h + 59min + 59s); > + VERIFY( res == WIDEN("22111:59:59") ); > + res = std::format(WIDEN("{:%I}"), 22111h + 59min + 59s); > + VERIFY( res == WIDEN("07") ); > + res = std::format(WIDEN("{:%p}"), 22111h + 59min + 59s); > + VERIFY( res == WIDEN("AM") ); > + > + res = std::format(WIDEN("{:%H}"), -22111h - 59min - 59s); > + VERIFY( res == WIDEN("-22111") ); > + res = std::format(WIDEN("{:%R}"), -22111h - 59min - 59s); > + VERIFY( res == WIDEN("-22111:59") ); > + res = std::format(WIDEN("{:%T}"), -22111h - 59min - 59s); > + VERIFY( res == WIDEN("-22111:59:59") ); > + res = std::format(WIDEN("{:%I}"), -22111h - 59min - 59s); > + VERIFY( res == WIDEN("-07") ); > + res = std::format(WIDEN("{:%p}"), -22111h - 59min - 59s); > + VERIFY( res == WIDEN("AM") ); > +} > + > +int main() > +{ > + test_year<char>(); > + test_month<char>(); > + test_day<char>(); > + test_date<char>(); > + test_weekday<char>(); > + test_hour<char>(); > + > +#ifdef _GLIBCXX_USE_WCHAR_T > + test_year<wchar_t>(); > + test_month<wchar_t>(); > + test_day<wchar_t>(); > + test_date<wchar_t>(); > + test_weekday<wchar_t>(); > + test_hour<wchar_t>(); > +#endif // _GLIBCXX_USE_WCHAR_T > +} > -- > 2.49.0 > >