https://gcc.gnu.org/g:c45cc9423d5fca4635865e1d4bc858a4a6f4d65b

commit r16-1170-gc45cc9423d5fca4635865e1d4bc858a4a6f4d65b
Author: Tomasz Kamiński <tkami...@redhat.com>
Date:   Mon Jun 2 09:06:56 2025 +0200

    libstdc++: Fix formatting of 3-digits months,day,weekday and hour [PR120481]
    
    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.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkami...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/chrono_io.h              | 217 +++++++++-----
 .../testsuite/std/time/format/empty_spec.cc        |  12 +-
 libstdc++-v3/testsuite/std/time/format/pr120481.cc | 324 +++++++++++++++++++++
 3 files changed, 480 insertions(+), 73 deletions(-)

diff --git a/libstdc++-v3/include/bits/chrono_io.h 
b/libstdc++-v3/include/bits/chrono_io.h
index 239f9c780094..9711a83cebed 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;
              __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;
        }
 
@@ -1331,8 +1383,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>
@@ -1517,12 +1569,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".
@@ -1541,6 +1593,41 @@ namespace __format
        };
       }
 
+      [[__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];
+      }
+
+      [[__gnu__::__always_inline__]]
+      // Returns decimal representation of __n.
+      // Returned string_view may point to __buf.
+      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);
+      }
+
+      [[__gnu__::__always_inline__]]
+      // Returns decimal representation of __n, padded to 2 digits.
+      // Returned string_view may point to __buf.
+      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.
diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc 
b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
index a3c64f5211ef..48f61ee13e43 100644
--- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
+++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
@@ -492,19 +492,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 000000000000..5878c5ba3970
--- /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
+}

Reply via email to