aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite/std
diff options
context:
space:
mode:
authorTomasz Kamiński <tkaminsk@redhat.com>2025-06-02 09:06:56 +0200
committerTomasz Kamiński <tkaminsk@redhat.com>2025-06-05 11:31:40 +0200
commitc45cc9423d5fca4635865e1d4bc858a4a6f4d65b (patch)
tree79bdbea6c90da92ed0bb4976816c5700fe132564 /libstdc++-v3/testsuite/std
parent61a6430cf663e3c980c2ee966f094fea7d99f8e7 (diff)
downloadgcc-c45cc9423d5fca4635865e1d4bc858a4a6f4d65b.zip
gcc-c45cc9423d5fca4635865e1d4bc858a4a6f4d65b.tar.gz
gcc-c45cc9423d5fca4635865e1d4bc858a4a6f4d65b.tar.bz2
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 <jwakely@redhat.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
Diffstat (limited to 'libstdc++-v3/testsuite/std')
-rw-r--r--libstdc++-v3/testsuite/std/time/format/empty_spec.cc12
-rw-r--r--libstdc++-v3/testsuite/std/time/format/pr120481.cc324
2 files changed, 328 insertions, 8 deletions
diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
index a3c64f5..48f61ee 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 0000000..5878c5ba
--- /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
+}