]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Formatting tests for std::chrono date types.
authorTomasz Kamiński <tkaminsk@redhat.com>
Thu, 9 Oct 2025 09:12:15 +0000 (11:12 +0200)
committerTomasz Kamiński <tkaminsk@redhat.com>
Thu, 9 Oct 2025 12:10:21 +0000 (14:10 +0200)
This covers year_month_day_last, year_month_weekday, year_month_weekday_last.

libstdc++-v3/ChangeLog:

* testsuite/std/time/year_month_day_last/io.cc: New formatting tests.
* testsuite/std/time/year_month_weekday/io.cc: Likewise.
* testsuite/std/time/year_month_weekday_last/io.cc: Likewise.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc

index 3241536a2e64eb72eff0445b8f54bc9508e16c81..de4f2479557255e966d3c540eb401e73b8b1f828 100644 (file)
@@ -22,9 +22,88 @@ test_ostream()
   VERIFY( ss.str() == "2023/juil./last" );
 }
 
+void
+test_format()
+{
+  using namespace std::chrono;
+
+  std::string s = std::format("{:%Y%t%C%%%y%n%j %b %a}", 2024y/January/last);
+  VERIFY( s == "2024\t20%24\n031 Jan Wed" );
+  std::wstring ws = std::format(L"{:%Y%t%C%%%y%n%j %b %a}", 2024y/December/last);
+  VERIFY( ws == L"2024\t20%24\n366 Dec Tue" );
+
+  s = std::format("{0:%Y-%m-%d} {0}", 2023y/May/last);
+  VERIFY( s == "2023-05-31 2023/May/last" );
+  s = std::format("{0:%Y-%m-%d} {0}", 2023y/month(13)/last);
+  VERIFY( s == "2023-13-30 2023/13 is not a valid month/last" );
+
+  s = std::format("{:%Y-%m-%d %j}", 2024y/February/last);
+  VERIFY( s == "2024-02-29 060" );
+  s = std::format("{:%Y-%m-%d %j}", 2023y/February/last);
+  VERIFY( s == "2023-02-28 059" );
+  s = std::format("{:%Y-%m-%d %j}", 2024y/September/last);
+  VERIFY( s == "2024-09-30 274" );
+
+  // %U: Week number for weeks starting on Sunday
+  s = std::format("{:%Y-U%U}", 2023y/January/last);
+  VERIFY( s == "2023-U05" );
+  s = std::format("{:%Y-U%U}", 2023y/December/last);
+  VERIFY( s == "2023-U53" );
+  // %W: Week number for weeks starting on Monday
+  s = std::format("{:%Y-W%W}", 2023y/January/last);
+  VERIFY( s == "2023-W05" );
+  s = std::format("{:%Y-W%W}", 2023y/December/last);
+  VERIFY( s == "2023-W52" );
+
+  // %G: ISO week-calendar year (ISO 8601)
+  // %V: ISO week number (ISO 8601).
+  s = std::format("{:%G-V%V}", 2019y/December/last);
+  VERIFY( s == "2020-V01" );
+  s = std::format("{:%G-V%V}", 2023y/January/last);
+  VERIFY( s == "2023-V05" );
+  s = std::format("{:%G-V%V}", 2023y/December/last);
+  VERIFY( s == "2023-V52" );
+
+  s = std::format("{:%F}", 2023y/July/last);
+  VERIFY( s == "2023-07-31" );
+  s = std::format("{:%x}", 2023y/July/last);
+  VERIFY( s == "07/31/23" );
+  s = std::format("{:L%x}", 2023y/July/last);
+  VERIFY( s == "07/31/23" );
+  std::locale loc_fr(ISO_8859(15,fr_FR));
+  s = std::format(loc_fr, "{:%x}", 2023y/July/last);
+  VERIFY( s == "07/31/23" );
+  s = std::format(loc_fr, "{:L%x}", 2023y/July/last);
+  VERIFY( s == "31/07/2023" || s == "31.07.2023" ); // depends on locale defs
+  s = std::format(loc_fr, "{:L}", 2023y/July/last);
+  VERIFY( s == "2023/juil./last" );
+
+  std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+  std::string_view my_specs = "aAbBCdDeFgGhjmuUVwWxyY";
+  for (char c : specs)
+  {
+    char fmt[] = { '{', ':', '%', c, '}' };
+    try
+    {
+      year_month_weekday ymw = 2023y/July/Thursday[2];
+      (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ymw));
+      // The call above should throw for any conversion-spec not in my_specs:
+      VERIFY(my_specs.find(c) != my_specs.npos);
+    }
+    catch (const std::format_error& e)
+    {
+      VERIFY(my_specs.find(c) == my_specs.npos);
+      std::string_view s = e.what();
+      // Libstdc++-specific message:
+      VERIFY(s.find("format argument does not contain the information "
+                   "required by the chrono-specs") != s.npos);
+    }
+  }
+}
+
 int main()
 {
   test_ostream();
-  // TODO: test_format();
+  test_format();
   // TODO: test_parse();
 }
index 65baf1d37ae360a6deb8217cef94bba274531889..92fd67022a243998b4a6903609bdb0d201f9b2c7 100644 (file)
@@ -34,9 +34,155 @@ test_ostream()
   VERIFY( ss.str() == "2023/juil./jeu.[2]" );
 }
 
+void
+test_format()
+{
+  using namespace std::chrono;
+
+  std::string s = std::format("{:%Y%t%C%%%y%n%j %b %a}", 2024y/January/Friday[2]);
+  VERIFY( s == "2024\t20%24\n012 Jan Fri" );
+  std::wstring ws = std::format(L"{:%Y%t%C%%%y%n%j %b %a}", 2024y/December/Monday[1]);
+  VERIFY( ws == L"2024\t20%24\n337 Dec Mon" );
+
+  s = std::format("{0:%Y-%m-%d} {0}", 2023y/May/Monday[1]);
+  VERIFY( s == "2023-05-01 2023/May/Mon[1]" );
+  s = std::format("{0:%Y-%m-%d} {0}", 2023y/month(13)/Monday[1]);
+  VERIFY( s == "2023-13-01 2023/13 is not a valid month/Mon[1]" );
+
+  s = std::format("{:%u %w}", Monday[1]);
+  VERIFY( s == "1 1" );
+  s = std::format("{:%u %w}", Sunday[2]);
+  VERIFY( s == "7 0" );
+  // 0 and 7 are both Sundays
+  s = std::format("{:%u %w}", weekday(0)[1]);
+  VERIFY( s == "7 0" );
+  s = std::format("{:%u %w}", weekday(7)[1]);
+  VERIFY( s == "7 0" );
+  s = std::format("{:%u %w}", weekday(9)[1]);
+  VERIFY( s == "9 9" );
+
+  s = std::format("{:%Y-%m-%d %j}", 2024y/February/Thursday[5]);
+  VERIFY( s == "2024-02-29 060" );
+  s = std::format("{:%Y-%m-%d %j}", 2023y/February/Tuesday[4]);
+  VERIFY( s == "2023-02-28 059" );
+  s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[1]);
+  VERIFY( s == "2024-09-01 245" );
+  s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[5]);
+  VERIFY( s == "2024-09-29 273" );
+  // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121929
+  // first weeks of next month
+  s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[6]);
+  VERIFY( s == "2024-09-06 280" );
+  s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[7]);
+  VERIFY( s == "2024-09-13 287" );
+  // last week on previous month
+  s = std::format("{:%Y-%m-%d %j}", 2024y/September/Saturday[0]);
+  VERIFY( s == "2024-09-31 244" );
+  s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[0]);
+  VERIFY( s == "2024-09-25 238" );
+
+  // %U: Week number for weeks starting on Sunday
+  s = std::format("{:%Y-U%U}", 2023y/January/Sunday[0]);
+  VERIFY( s == "2023-U00" );
+  s = std::format("{:%Y-U%U}", 2023y/January/Sunday[1]);
+  VERIFY( s == "2023-U01" );
+  s = std::format("{:%Y-U%U}", 2023y/January/Sunday[4]);
+  VERIFY( s == "2023-U04" );
+  s = std::format("{:%Y-U%U}", 2023y/January/Sunday[7]);
+  VERIFY( s == "2023-U07" );
+  s = std::format("{:%Y-U%U}", 2023y/December/Sunday[0]);
+  VERIFY( s == "2023-U48" );
+  s = std::format("{:%Y-U%U}", 2023y/December/Sunday[1]);
+  VERIFY( s == "2023-U49" );
+  s = std::format("{:%Y-U%U}", 2023y/December/Sunday[4]);
+  VERIFY( s == "2023-U52" );
+  s = std::format("{:%Y-U%U}", 2023y/December/Sunday[7]);
+  VERIFY( s == "2023-U55" );
+  // %W: Week number for weeks starting on Monday
+  s = std::format("{:%Y-W%W}", 2023y/January/Monday[0]);
+  VERIFY( s == "2023-W00" );
+  s = std::format("{:%Y-W%W}", 2023y/January/Monday[1]);
+  VERIFY( s == "2023-W01" );
+  s = std::format("{:%Y-W%W}", 2023y/January/Monday[4]);
+  VERIFY( s == "2023-W04" );
+  s = std::format("{:%Y-W%W}", 2023y/January/Monday[7]);
+  VERIFY( s == "2023-W07" );
+  s = std::format("{:%Y-W%W}", 2023y/December/Monday[0]);
+  VERIFY( s == "2023-W48" );
+  s = std::format("{:%Y-W%W}", 2023y/December/Monday[1]);
+  VERIFY( s == "2023-W49" );
+  s = std::format("{:%Y-W%W}", 2023y/December/Monday[4]);
+  VERIFY( s == "2023-W52" );
+  s = std::format("{:%Y-W%W}", 2023y/December/Monday[7]);
+  VERIFY( s == "2023-W55" );
+  // First Sunday precedes first Monday, so happens on
+  // last week of previous month and thus year
+  s = std::format("{:%Y-W%W}", 2023y/January/Sunday[1]);
+  VERIFY( s == "2023-W00" );
+  // Last Sunday of pevious year happens on second to
+  // last week on previous year
+  s = std::format("{:%Y-W%W}", 2023y/January/Sunday[0]);
+  VERIFY( s == "2023-W99" );
+
+  // %G: ISO week-calendar year (ISO 8601)
+  // %V: ISO week number (ISO 8601).
+  s = std::format("{:%G-V%V}", 2023y/January/Monday[0]);
+  VERIFY( s == "2022-V52" );
+  s = std::format("{:%G-V%V}", 2023y/January/Monday[1]);
+  VERIFY( s == "2023-V01" );
+  s = std::format("{:%G-V%V}", 2023y/January/Monday[4]);
+  VERIFY( s == "2023-V04" );
+  s = std::format("{:%G-V%V}", 2023y/January/Monday[7]);
+  VERIFY( s == "2023-V07" );
+  s = std::format("{:%G-V%V}", 2023y/December/Friday[0]);
+  VERIFY( s == "2023-V47" );
+  s = std::format("{:%G-V%V}", 2023y/December/Friday[1]);
+  VERIFY( s == "2023-V48" );
+  s = std::format("{:%G-V%V}", 2023y/December/Friday[5]);
+  VERIFY( s == "2023-V52" );
+  s = std::format("{:%G-V%V}", 2023y/December/Friday[6]);
+  VERIFY( s == "2024-V01" );
+
+  s = std::format("{:%F}", 2023y/July/Thursday[2]);
+  VERIFY( s == "2023-07-13" );
+  s = std::format("{:%x}", 2023y/July/Thursday[2]);
+  VERIFY( s == "07/13/23" );
+  s = std::format("{:L%x}", 2023y/July/Thursday[2]);
+  VERIFY( s == "07/13/23" );
+  std::locale loc_fr(ISO_8859(15,fr_FR));
+  s = std::format(loc_fr, "{:%x}", 2023y/July/Thursday[2]);
+  VERIFY( s == "07/13/23" );
+  s = std::format(loc_fr, "{:L%x}", 2023y/July/Thursday[2]);
+  VERIFY( s == "13/07/2023" || s == "13.07.2023" ); // depends on locale defs
+  s = std::format(loc_fr, "{:L}", 2023y/July/Thursday[2]);
+  VERIFY( s == "2023/juil./jeu.[2]" );
+
+  std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+  std::string_view my_specs = "aAbBCdDeFgGhjmuUVwWxyY";
+  for (char c : specs)
+  {
+    char fmt[] = { '{', ':', '%', c, '}' };
+    try
+    {
+      year_month_weekday ymw = 2023y/July/Thursday[2];
+      (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ymw));
+      // The call above should throw for any conversion-spec not in my_specs:
+      VERIFY(my_specs.find(c) != my_specs.npos);
+    }
+    catch (const std::format_error& e)
+    {
+      VERIFY(my_specs.find(c) == my_specs.npos);
+      std::string_view s = e.what();
+      // Libstdc++-specific message:
+      VERIFY(s.find("format argument does not contain the information "
+                   "required by the chrono-specs") != s.npos);
+    }
+  }
+}
+
 int main()
 {
   test_ostream();
-  // TODO: test_format();
+  test_format();
   // TODO: test_parse();
 }
index 17f2244420d723d20058b38f178d751862c20dfa..983589720b5e05f0b6b72cb44429889b92dd77ec 100644 (file)
@@ -30,9 +30,104 @@ test_ostream()
   VERIFY( ss.str() == "2023/juil./jeu.[last]" );
 }
 
+void
+test_format()
+{
+  using namespace std::chrono;
+
+  std::string s = std::format("{:%Y%t%C%%%y%n%j %b %a}", 2024y/January/Friday[last]);
+  VERIFY( s == "2024\t20%24\n026 Jan Fri" );
+  std::wstring ws = std::format(L"{:%Y%t%C%%%y%n%j %b %a}", 2024y/December/Monday[last]);
+  VERIFY( ws == L"2024\t20%24\n365 Dec Mon" );
+
+  s = std::format("{0:%Y-%m-%d} {0}", 2023y/May/Monday[last]);
+  VERIFY( s == "2023-05-29 2023/May/Mon[last]" );
+  s = std::format("{0:%Y-%m-%d} {0}", 2023y/month(13)/Monday[last]);
+  VERIFY( s == "2023-13-29 2023/13 is not a valid month/Mon[last]" );
+
+  s = std::format("{:%u %w}", Monday[last]);
+  VERIFY( s == "1 1" );
+  s = std::format("{:%u %w}", Sunday[2]);
+  VERIFY( s == "7 0" );
+  // 0 and 7 are both Sundays
+  s = std::format("{:%u %w}", weekday(0)[last]);
+  VERIFY( s == "7 0" );
+  s = std::format("{:%u %w}", weekday(7)[last]);
+  VERIFY( s == "7 0" );
+  s = std::format("{:%u %w}", weekday(9)[last]);
+  VERIFY( s == "9 9" );
+
+  s = std::format("{:%Y-%m-%d %j}", 2024y/February/Thursday[last]);
+  VERIFY( s == "2024-02-29 060" );
+  s = std::format("{:%Y-%m-%d %j}", 2023y/February/Tuesday[last]);
+  VERIFY( s == "2023-02-28 059" );
+  s = std::format("{:%Y-%m-%d %j}", 2024y/September/Sunday[last]);
+  VERIFY( s == "2024-09-29 273" );
+
+  // %U: Week number for weeks starting on Sunday
+  s = std::format("{:%Y-U%U}", 2023y/January/Sunday[last]);
+  VERIFY( s == "2023-U05" );
+  s = std::format("{:%Y-U%U}", 2023y/December/Sunday[last]);
+  VERIFY( s == "2023-U53" );
+  // %W: Week number for weeks starting on Monday
+  s = std::format("{:%Y-W%W}", 2023y/January/Monday[last]);
+  VERIFY( s == "2023-W05" );
+  s = std::format("{:%Y-W%W}", 2023y/December/Monday[last]);
+  VERIFY( s == "2023-W52" );
+  s = std::format("{:%Y-W%W}", 2023y/January/Sunday[last]);
+  VERIFY( s == "2023-W04" );
+  s = std::format("{:%Y-W%W}", 2023y/December/Sunday[last]);
+  VERIFY( s == "2023-W52" );
+
+  // %G: ISO week-calendar year (ISO 8601)
+  // %V: ISO week number (ISO 8601).
+  s = std::format("{:%G-V%V}", 2019y/December/Tuesday[last]);
+  VERIFY( s == "2020-V01" );
+  s = std::format("{:%G-V%V}", 2023y/January/Monday[last]);
+  VERIFY( s == "2023-V05" );
+  s = std::format("{:%G-V%V}", 2023y/December/Friday[last]);
+  VERIFY( s == "2023-V52" );
+
+  s = std::format("{:%F}", 2023y/July/Thursday[last]);
+  VERIFY( s == "2023-07-27" );
+  s = std::format("{:%x}", 2023y/July/Thursday[last]);
+  VERIFY( s == "07/27/23" );
+  s = std::format("{:L%x}", 2023y/July/Thursday[last]);
+  VERIFY( s == "07/27/23" );
+  std::locale loc_fr(ISO_8859(15,fr_FR));
+  s = std::format(loc_fr, "{:%x}", 2023y/July/Thursday[last]);
+  VERIFY( s == "07/27/23" );
+  s = std::format(loc_fr, "{:L%x}", 2023y/July/Thursday[last]);
+  VERIFY( s == "27/07/2023" || s == "27.07.2023" ); // depends on locale defs
+  s = std::format(loc_fr, "{:L}", 2023y/July/Thursday[last]);
+  VERIFY( s == "2023/juil./jeu.[last]" );
+
+  std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
+  std::string_view my_specs = "aAbBCdDeFgGhjmuUVwWxyY";
+  for (char c : specs)
+  {
+    char fmt[] = { '{', ':', '%', c, '}' };
+    try
+    {
+      year_month_weekday ymw = 2023y/July/Thursday[2];
+      (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ymw));
+      // The call above should throw for any conversion-spec not in my_specs:
+      VERIFY(my_specs.find(c) != my_specs.npos);
+    }
+    catch (const std::format_error& e)
+    {
+      VERIFY(my_specs.find(c) == my_specs.npos);
+      std::string_view s = e.what();
+      // Libstdc++-specific message:
+      VERIFY(s.find("format argument does not contain the information "
+                   "required by the chrono-specs") != s.npos);
+    }
+  }
+}
+
 int main()
 {
   test_ostream();
-  // TODO: test_format();
+  test_format();
   // TODO: test_parse();
 }