From 25a9beedb0c47e3e0f1da4a7fac0773a43e33754 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Sat, 2 Dec 2023 19:12:49 +0400 Subject: [PATCH 1/3] test: add a fallback definition for std::chrono::days --- test/chrono-test.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/chrono-test.cc b/test/chrono-test.cc index b562a50ea4bf..7068c9799755 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -24,6 +24,12 @@ using testing::Contains; # define FMT_HAS_C99_STRFTIME 1 #endif +#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907L +using days = std::chrono::days; +#else +using days = std::chrono::duration>; +#endif + auto make_tm() -> std::tm { auto time = std::tm(); time.tm_mday = 1; From 69f01fe893e67a887e02267608a1693e41f57c50 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Sat, 2 Dec 2023 19:11:31 +0400 Subject: [PATCH 2/3] test: use our std::chrono::days fallback instead of >=C++17 conditional --- test/chrono-test.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 7068c9799755..1eb34118daeb 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -462,9 +462,7 @@ TEST(chrono_test, format_default) { fmt::format("{}", std::chrono::duration(42))); EXPECT_EQ("42min", fmt::format("{}", std::chrono::minutes(42))); EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42))); -# if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907L - EXPECT_EQ("42d", fmt::format("{}", std::chrono::days(42))); -# endif + EXPECT_EQ("42d", fmt::format("{}", days(42))); EXPECT_EQ( "42[15]s", fmt::format("{}", std::chrono::duration>(42))); From 78a611777e6cba113953cf626a4a6a36d92f9e55 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Sat, 2 Dec 2023 19:12:36 +0400 Subject: [PATCH 3/3] Implement `%j` specifier for std::chrono::duration This adds support for `%j` presentation type for duration types: > "If the type being formatted is a specialization of duration, the decimal number of days without padding." Fixes #3643. --- include/fmt/chrono.h | 8 +++++++- test/chrono-test.cc | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 9b4f9d4ed5ab..57cd0b701cfe 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1622,6 +1622,7 @@ struct chrono_format_checker : null_chrono_spec_handler { template FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_day_of_year() {} FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} @@ -1806,6 +1807,7 @@ struct chrono_formatter { return true; } + Rep days() const { return static_cast(s.count() / 86400); } Rep hour() const { return static_cast(mod((s.count() / 3600), 24)); } Rep hour12() const { @@ -1884,10 +1886,14 @@ struct chrono_formatter { void on_dec0_week_of_year(numeric_system) {} void on_dec1_week_of_year(numeric_system) {} void on_iso_week_of_year(numeric_system) {} - void on_day_of_year() {} void on_day_of_month(numeric_system) {} void on_day_of_month_space(numeric_system) {} + void on_day_of_year() { + if (handle_nan_inf()) return; + write(days(), 0); + } + void on_24_hour(numeric_system ns, pad_type pad) { if (handle_nan_inf()) return; diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 1eb34118daeb..cb672816c93d 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -537,6 +537,8 @@ TEST(chrono_test, format_specs) { EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(24))); EXPECT_EQ("04", fmt::format("{:%I}", std::chrono::hours(4))); EXPECT_EQ("02", fmt::format("{:%I}", std::chrono::hours(14))); + EXPECT_EQ("12345", fmt::format("{:%j}", days(12345))); + EXPECT_EQ("12345", fmt::format("{:%j}", std::chrono::hours(12345 * 24 + 12))); EXPECT_EQ("03:25:45", fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345))); EXPECT_EQ("03:25", fmt::format("{:%R}", std::chrono::seconds(12345)));