[PATCH] libstdc++: Fix formatting of 3-digits months, day, weekday and hour [PR120481]
Tomasz Kaminski
tkaminsk@redhat.com
Mon Jun 2 11:28:47 GMT 2025
On Mon, Jun 2, 2025 at 1:21 PM Tomasz Kamiński <tkaminsk@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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250602/31e02e8b/attachment-0001.htm>
More information about the Libstdc++
mailing list