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
>
>

Reply via email to