[PATCH] libstdc++: Formatting tests for std::chrono date types.
Jonathan Wakely
jwakely@redhat.com
Thu Oct 9 11:32:10 GMT 2025
On Thu, 9 Oct 2025 at 11:38, Tomasz Kamiński <tkaminsk@redhat.com> wrote:
>
> 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.
OK thanks
>
> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
> ---
> Tested on x86_64-linux locally. OK for trunk?
>
> .../std/time/year_month_day_last/io.cc | 81 +++++++++-
> .../std/time/year_month_weekday/io.cc | 148 +++++++++++++++++-
> .../std/time/year_month_weekday_last/io.cc | 97 +++++++++++-
> 3 files changed, 323 insertions(+), 3 deletions(-)
>
> diff --git a/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc b/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
> index 3241536a2e6..de4f2479557 100644
> --- a/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
> +++ b/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
> @@ -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();
> }
> diff --git a/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc b/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
> index 65baf1d37ae..92fd67022a2 100644
> --- a/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
> +++ b/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
> @@ -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();
> }
> diff --git a/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
> index 17f2244420d..983589720b5 100644
> --- a/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
> +++ b/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
> @@ -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();
> }
> --
> 2.51.0
>
More information about the Libstdc++
mailing list