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