[PATCH] libstdc++: Fix formatting of 3-digits months, day, weekday and hour [PR120481]

Jonathan Wakely jwakely@redhat.com
Wed Jun 4 20:43:46 GMT 2025


On 02/06/25 13:19 +0200, Tomasz Kamiński 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?

Three minor comments about comments below - OK for trunk with those
changes.


> 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;
> 	      __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.

Please put the comment before the attribute.

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

s/represenation/representation/

>+      // 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:

A single space character has been lost at the start of this line :-)

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



More information about the Libstdc++ mailing list