From f53632971a0abf7e4b2c1e7278e4d797faa072b4 Mon Sep 17 00:00:00 2001 From: Zaheen Jamil Date: Fri, 24 May 2024 22:53:18 +1000 Subject: [PATCH 1/8] Add glibc ext for week of year and day of month --- include/fmt/chrono.h | 77 ++++++++++++++++++-------------------------- test/chrono-test.cc | 22 ++++++++++++- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index d61b083273f9..20c3e3065e49 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -795,22 +795,22 @@ FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, break; // Day of the year/month: case 'U': - handler.on_dec0_week_of_year(numeric_system::standard); + handler.on_dec0_week_of_year(numeric_system::standard, pad); break; case 'W': - handler.on_dec1_week_of_year(numeric_system::standard); + handler.on_dec1_week_of_year(numeric_system::standard, pad); break; case 'V': - handler.on_iso_week_of_year(numeric_system::standard); + handler.on_iso_week_of_year(numeric_system::standard, pad); break; case 'j': handler.on_day_of_year(); break; case 'd': - handler.on_day_of_month(numeric_system::standard); + handler.on_day_of_month(numeric_system::standard, pad); break; case 'e': - handler.on_day_of_month_space(numeric_system::standard); + handler.on_day_of_month(numeric_system::standard, pad_type::space); break; // Hour, minute, second: case 'H': @@ -907,19 +907,19 @@ FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, handler.on_dec_month(numeric_system::alternative); break; case 'U': - handler.on_dec0_week_of_year(numeric_system::alternative); + handler.on_dec0_week_of_year(numeric_system::alternative, pad); break; case 'W': - handler.on_dec1_week_of_year(numeric_system::alternative); + handler.on_dec1_week_of_year(numeric_system::alternative, pad); break; case 'V': - handler.on_iso_week_of_year(numeric_system::alternative); + handler.on_iso_week_of_year(numeric_system::alternative, pad); break; case 'd': - handler.on_day_of_month(numeric_system::alternative); + handler.on_day_of_month(numeric_system::alternative, pad); break; case 'e': - handler.on_day_of_month_space(numeric_system::alternative); + handler.on_day_of_month(numeric_system::alternative, pad_type::space); break; case 'w': handler.on_dec0_weekday(numeric_system::alternative); @@ -972,12 +972,11 @@ template struct null_chrono_spec_handler { FMT_CONSTEXPR void on_abbr_month() { unsupported(); } FMT_CONSTEXPR void on_full_month() { unsupported(); } FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type pad) { unsupported(); } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type pad) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type pad) { unsupported(); } FMT_CONSTEXPR void on_day_of_year() { unsupported(); } - FMT_CONSTEXPR void on_day_of_month(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_day_of_month_space(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type pad) { unsupported(); } FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } @@ -1015,12 +1014,11 @@ struct tm_format_checker : null_chrono_spec_handler { FMT_CONSTEXPR void on_abbr_month() {} FMT_CONSTEXPR void on_full_month() {} FMT_CONSTEXPR void on_dec_month(numeric_system) {} - FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) {} - FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) {} - FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) {} FMT_CONSTEXPR void on_day_of_year() {} - FMT_CONSTEXPR void on_day_of_month(numeric_system) {} - FMT_CONSTEXPR void on_day_of_month_space(numeric_system) {} + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) {} 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) {} @@ -1454,7 +1452,7 @@ class tm_writer { *out_++ = ' '; on_abbr_month(); *out_++ = ' '; - on_day_of_month_space(numeric_system::standard); + on_day_of_month(numeric_system::standard, pad_type::space); *out_++ = ' '; on_iso_time(); *out_++ = ' '; @@ -1541,24 +1539,24 @@ class tm_writer { format_localized('m', 'O'); } - void on_dec0_week_of_year(numeric_system ns) { + void on_dec0_week_of_year(numeric_system ns, pad_type pad) { if (is_classic_ || ns == numeric_system::standard) - return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week); + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week, pad); format_localized('U', 'O'); } - void on_dec1_week_of_year(numeric_system ns) { + void on_dec1_week_of_year(numeric_system ns, pad_type pad) { if (is_classic_ || ns == numeric_system::standard) { auto wday = tm_wday(); write2((tm_yday() + days_per_week - (wday == 0 ? (days_per_week - 1) : (wday - 1))) / - days_per_week); + days_per_week, pad); } else { format_localized('W', 'O'); } } - void on_iso_week_of_year(numeric_system ns) { + void on_iso_week_of_year(numeric_system ns, pad_type pad) { if (is_classic_ || ns == numeric_system::standard) - return write2(tm_iso_week_of_year()); + return write2(tm_iso_week_of_year(), pad); format_localized('V', 'O'); } @@ -1572,20 +1570,10 @@ class tm_writer { write1(yday / 100); write2(yday % 100); } - void on_day_of_month(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday()); + void on_day_of_month(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday(), pad); format_localized('d', 'O'); } - void on_day_of_month_space(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) { - auto mday = to_unsigned(tm_mday()) % 100; - const char* d2 = digits2(mday); - *out_++ = mday < 10 ? ' ' : d2[0]; - *out_++ = d2[1]; - } else { - format_localized('e', 'O'); - } - } void on_24_hour(numeric_system ns, pad_type pad) { if (is_classic_ || ns == numeric_system::standard) @@ -1933,11 +1921,10 @@ struct chrono_formatter { void on_iso_week_based_year() {} void on_iso_week_based_short_year() {} void on_dec_month(numeric_system) {} - 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_month(numeric_system) {} - void on_day_of_month_space(numeric_system) {} + void on_dec0_week_of_year(numeric_system, pad_type pad) {} + void on_dec1_week_of_year(numeric_system, pad_type pad) {} + void on_iso_week_of_year(numeric_system, pad_type pad) {} + void on_day_of_month(numeric_system, pad_type pad) {} void on_day_of_year() { if (handle_nan_inf()) return; @@ -2156,7 +2143,7 @@ struct formatter : private formatter { if (use_tm_formatter_) return formatter::format(time, ctx); detail::get_locale loc(false, ctx.locale()); auto w = detail::tm_writer(loc, ctx.out(), time); - w.on_day_of_month(detail::numeric_system::standard); + w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::unspecified); return w.out(); } }; diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 1055c7982097..0a70210d88de 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -1004,12 +1004,32 @@ TEST(chrono_test, glibc_extensions) { } { - const auto d = std::chrono::duration(3.14); + auto d = std::chrono::duration(3.14); EXPECT_EQ(fmt::format("{:%S}", d), "03.140000"); EXPECT_EQ(fmt::format("{:%0S}", d), "03.140000"); EXPECT_EQ(fmt::format("{:%_S}", d), " 3.140000"); EXPECT_EQ(fmt::format("{:%-S}", d), "3.140000"); } + + { + auto t = std::tm(); + t.tm_yday = 7; + EXPECT_EQ(fmt::format("{:%U,%W,%V}", t), "02,01,01"); + EXPECT_EQ(fmt::format("{:%0U,%0W,%0V}", t), "02,01,01"); + EXPECT_EQ(fmt::format("{:%_U,%_W,%_V}", t), " 2, 1, 1"); + EXPECT_EQ(fmt::format("{:%-U,%-W,%-V}", t), "2,1,1"); + } + + { + auto t = std::tm(); + t.tm_mday = 7; + EXPECT_EQ(fmt::format("{:%d}", t), "07"); + EXPECT_EQ(fmt::format("{:%0d}", t), "07"); + EXPECT_EQ(fmt::format("{:%_d}", t), " 7"); + EXPECT_EQ(fmt::format("{:%-d}", t), "7"); + + EXPECT_EQ(fmt::format("{:%e}", t), " 7"); + } } TEST(chrono_test, out_of_range) { From 2627fa5870bb2f7ec973a4f16b2c3552bf7dca2d Mon Sep 17 00:00:00 2001 From: Zaheen Jamil Date: Fri, 24 May 2024 23:36:21 +1000 Subject: [PATCH 2/8] Add %k, %l format specifiers --- include/fmt/chrono.h | 12 ++++++++++++ test/chrono-test.cc | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 20c3e3065e49..e89092b8fbeb 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -819,6 +819,12 @@ FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, case 'I': handler.on_12_hour(numeric_system::standard, pad); break; + case 'k': + handler.on_24_hour(numeric_system::standard, pad_type::space); + break; + case 'l': + handler.on_12_hour(numeric_system::standard, pad_type::space); + break; case 'M': handler.on_minute(numeric_system::standard, pad); break; @@ -936,6 +942,12 @@ FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, case 'M': handler.on_minute(numeric_system::alternative, pad); break; + case 'k': + handler.on_24_hour(numeric_system::alternative, pad_type::space); + break; + case 'l': + handler.on_12_hour(numeric_system::alternative, pad_type::space); + break; case 'S': handler.on_second(numeric_system::alternative, pad); break; diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 0a70210d88de..a38bccca6ad1 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -980,6 +980,8 @@ TEST(chrono_test, glibc_extensions) { EXPECT_EQ(fmt::format("{:%0OI,%0OH,%0OM,%0OS}", d), "01,01,02,03"); EXPECT_EQ(fmt::format("{:%_OI,%_OH,%_OM,%_OS}", d), " 1, 1, 2, 3"); EXPECT_EQ(fmt::format("{:%-OI,%-OH,%-OM,%-OS}", d), "1,1,2,3"); + + EXPECT_EQ(fmt::format("{:%k,%l}", d), " 1, 1"); } { @@ -993,6 +995,8 @@ TEST(chrono_test, glibc_extensions) { EXPECT_EQ(fmt::format("{:%0OI,%0OH,%0OM,%0OS}", tm), "01,01,02,03"); EXPECT_EQ(fmt::format("{:%_OI,%_OH,%_OM,%_OS}", tm), " 1, 1, 2, 3"); EXPECT_EQ(fmt::format("{:%-OI,%-OH,%-OM,%-OS}", tm), "1,1,2,3"); + + EXPECT_EQ(fmt::format("{:%k,%l}", tm), " 1, 1"); } { From cc359a6361771de469bb2a212034eeb75998f92e Mon Sep 17 00:00:00 2001 From: Zaheen Jamil Date: Sun, 26 May 2024 07:01:33 +1000 Subject: [PATCH 3/8] Make CI happy and ran clang-format --- include/fmt/chrono.h | 86 ++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index e89092b8fbeb..7cce722e1f40 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -74,8 +74,8 @@ template ::value && std::numeric_limits::is_signed == std::numeric_limits::is_signed)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) - -> To { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, + int& ec) -> To { ec = 0; using F = std::numeric_limits; using T = std::numeric_limits; @@ -104,8 +104,8 @@ template ::value && std::numeric_limits::is_signed != std::numeric_limits::is_signed)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) - -> To { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, + int& ec) -> To { ec = 0; using F = std::numeric_limits; using T = std::numeric_limits; @@ -137,8 +137,8 @@ FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) template ::value)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) - -> To { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, + int& ec) -> To { ec = 0; return from; } // function @@ -395,8 +395,8 @@ void write_codecvt(codecvt_result& out, string_view in_buf, } template -auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) - -> OutputIt { +auto write_encoded_tm_str(OutputIt out, string_view in, + const std::locale& loc) -> OutputIt { if (detail::use_utf8() && loc != get_classic_locale()) { // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and // gcc-4. @@ -425,8 +425,8 @@ auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) template ::value)> -auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) - -> OutputIt { +auto write_tm_str(OutputIt out, string_view sv, + const std::locale& loc) -> OutputIt { codecvt_result unit; write_codecvt(unit, sv, loc); return copy(unit.buf, unit.end, out); @@ -434,8 +434,8 @@ auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) template ::value)> -auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) - -> OutputIt { +auto write_tm_str(OutputIt out, string_view sv, + const std::locale& loc) -> OutputIt { return write_encoded_tm_str(out, sv, loc); } @@ -503,9 +503,8 @@ auto fmt_duration_cast(std::chrono::duration from) -> To { } template -auto to_time_t( - std::chrono::time_point time_point) - -> std::time_t { +auto to_time_t(std::chrono::time_point + time_point) -> std::time_t { // Cannot use std::chrono::system_clock::to_time_t since this would first // require a cast to std::chrono::system_clock::time_point, which could // overflow. @@ -607,9 +606,8 @@ inline auto gmtime(std::time_t time) -> std::tm { } template -inline auto gmtime( - std::chrono::time_point time_point) - -> std::tm { +inline auto gmtime(std::chrono::time_point + time_point) -> std::tm { return gmtime(detail::to_time_t(time_point)); } @@ -984,11 +982,19 @@ template struct null_chrono_spec_handler { FMT_CONSTEXPR void on_abbr_month() { unsupported(); } FMT_CONSTEXPR void on_full_month() { unsupported(); } FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type pad) { unsupported(); } - FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type pad) { unsupported(); } - FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type pad) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) { + unsupported(); + } FMT_CONSTEXPR void on_day_of_year() { unsupported(); } - FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type pad) { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) { + unsupported(); + } FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } @@ -1553,7 +1559,8 @@ class tm_writer { void on_dec0_week_of_year(numeric_system ns, pad_type pad) { if (is_classic_ || ns == numeric_system::standard) - return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week, pad); + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week, + pad); format_localized('U', 'O'); } void on_dec1_week_of_year(numeric_system ns, pad_type pad) { @@ -1561,7 +1568,8 @@ class tm_writer { auto wday = tm_wday(); write2((tm_yday() + days_per_week - (wday == 0 ? (days_per_week - 1) : (wday - 1))) / - days_per_week, pad); + days_per_week, + pad); } else { format_localized('W', 'O'); } @@ -1583,7 +1591,8 @@ class tm_writer { write2(yday % 100); } void on_day_of_month(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday(), pad); + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mday(), pad); format_localized('d', 'O'); } @@ -1933,10 +1942,10 @@ struct chrono_formatter { void on_iso_week_based_year() {} void on_iso_week_based_short_year() {} void on_dec_month(numeric_system) {} - void on_dec0_week_of_year(numeric_system, pad_type pad) {} - void on_dec1_week_of_year(numeric_system, pad_type pad) {} - void on_iso_week_of_year(numeric_system, pad_type pad) {} - void on_day_of_month(numeric_system, pad_type pad) {} + void on_dec0_week_of_year(numeric_system, pad_type) {} + void on_dec1_week_of_year(numeric_system, pad_type) {} + void on_iso_week_of_year(numeric_system, pad_type) {} + void on_day_of_month(numeric_system, pad_type) {} void on_day_of_year() { if (handle_nan_inf()) return; @@ -2155,7 +2164,8 @@ struct formatter : private formatter { if (use_tm_formatter_) return formatter::format(time, ctx); detail::get_locale loc(false, ctx.locale()); auto w = detail::tm_writer(loc, ctx.out(), time); - w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::unspecified); + w.on_day_of_month(detail::numeric_system::standard, + detail::pad_type::unspecified); return w.out(); } }; @@ -2230,8 +2240,8 @@ struct formatter : private formatter { } template - auto format(year_month_day val, FormatContext& ctx) const - -> decltype(ctx.out()) { + auto format(year_month_day val, + FormatContext& ctx) const -> decltype(ctx.out()) { auto time = std::tm(); time.tm_year = static_cast(val.year()) - 1900; time.tm_mon = static_cast(static_cast(val.month())) - 1; @@ -2281,8 +2291,8 @@ struct formatter, Char> { } template - auto format(std::chrono::duration d, FormatContext& ctx) const - -> decltype(ctx.out()) { + auto format(std::chrono::duration d, + FormatContext& ctx) const -> decltype(ctx.out()) { auto specs = specs_; auto precision = specs.precision; specs.precision = -1; @@ -2353,8 +2363,8 @@ struct formatter, Char> } template - auto format(std::chrono::local_time val, FormatContext& ctx) const - -> decltype(ctx.out()) { + auto format(std::chrono::local_time val, + FormatContext& ctx) const -> decltype(ctx.out()) { using period = typename Duration::period; if (period::num != 1 || period::den != 1 || std::is_floating_point::value) { @@ -2431,8 +2441,8 @@ template struct formatter { } template - auto format(const std::tm& tm, FormatContext& ctx) const - -> decltype(ctx.out()) { + auto format(const std::tm& tm, + FormatContext& ctx) const -> decltype(ctx.out()) { return do_format(tm, ctx, nullptr); } }; From 88dd6de611253498750b1cf3c76f1885dc179858 Mon Sep 17 00:00:00 2001 From: Zaheen Jamil Date: Sun, 26 May 2024 18:20:21 +1000 Subject: [PATCH 4/8] Ran clang-format 17 --- include/fmt/chrono.h | 50 +++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 7cce722e1f40..1927f3271696 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -74,8 +74,8 @@ template ::value && std::numeric_limits::is_signed == std::numeric_limits::is_signed)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, - int& ec) -> To { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { ec = 0; using F = std::numeric_limits; using T = std::numeric_limits; @@ -104,8 +104,8 @@ template ::value && std::numeric_limits::is_signed != std::numeric_limits::is_signed)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, - int& ec) -> To { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { ec = 0; using F = std::numeric_limits; using T = std::numeric_limits; @@ -137,8 +137,8 @@ FMT_CONSTEXPR auto lossless_integral_conversion(const From from, template ::value)> -FMT_CONSTEXPR auto lossless_integral_conversion(const From from, - int& ec) -> To { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { ec = 0; return from; } // function @@ -395,8 +395,8 @@ void write_codecvt(codecvt_result& out, string_view in_buf, } template -auto write_encoded_tm_str(OutputIt out, string_view in, - const std::locale& loc) -> OutputIt { +auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) + -> OutputIt { if (detail::use_utf8() && loc != get_classic_locale()) { // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and // gcc-4. @@ -425,8 +425,8 @@ auto write_encoded_tm_str(OutputIt out, string_view in, template ::value)> -auto write_tm_str(OutputIt out, string_view sv, - const std::locale& loc) -> OutputIt { +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { codecvt_result unit; write_codecvt(unit, sv, loc); return copy(unit.buf, unit.end, out); @@ -434,8 +434,8 @@ auto write_tm_str(OutputIt out, string_view sv, template ::value)> -auto write_tm_str(OutputIt out, string_view sv, - const std::locale& loc) -> OutputIt { +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { return write_encoded_tm_str(out, sv, loc); } @@ -503,8 +503,9 @@ auto fmt_duration_cast(std::chrono::duration from) -> To { } template -auto to_time_t(std::chrono::time_point - time_point) -> std::time_t { +auto to_time_t( + std::chrono::time_point time_point) + -> std::time_t { // Cannot use std::chrono::system_clock::to_time_t since this would first // require a cast to std::chrono::system_clock::time_point, which could // overflow. @@ -606,8 +607,9 @@ inline auto gmtime(std::time_t time) -> std::tm { } template -inline auto gmtime(std::chrono::time_point - time_point) -> std::tm { +inline auto gmtime( + std::chrono::time_point time_point) + -> std::tm { return gmtime(detail::to_time_t(time_point)); } @@ -2240,8 +2242,8 @@ struct formatter : private formatter { } template - auto format(year_month_day val, - FormatContext& ctx) const -> decltype(ctx.out()) { + auto format(year_month_day val, FormatContext& ctx) const + -> decltype(ctx.out()) { auto time = std::tm(); time.tm_year = static_cast(val.year()) - 1900; time.tm_mon = static_cast(static_cast(val.month())) - 1; @@ -2291,8 +2293,8 @@ struct formatter, Char> { } template - auto format(std::chrono::duration d, - FormatContext& ctx) const -> decltype(ctx.out()) { + auto format(std::chrono::duration d, FormatContext& ctx) const + -> decltype(ctx.out()) { auto specs = specs_; auto precision = specs.precision; specs.precision = -1; @@ -2363,8 +2365,8 @@ struct formatter, Char> } template - auto format(std::chrono::local_time val, - FormatContext& ctx) const -> decltype(ctx.out()) { + auto format(std::chrono::local_time val, FormatContext& ctx) const + -> decltype(ctx.out()) { using period = typename Duration::period; if (period::num != 1 || period::den != 1 || std::is_floating_point::value) { @@ -2441,8 +2443,8 @@ template struct formatter { } template - auto format(const std::tm& tm, - FormatContext& ctx) const -> decltype(ctx.out()) { + auto format(const std::tm& tm, FormatContext& ctx) const + -> decltype(ctx.out()) { return do_format(tm, ctx, nullptr); } }; From 62834cce6c4c0b38e15eff6fa81d038a3603143b Mon Sep 17 00:00:00 2001 From: Zaheen Jamil Date: Tue, 28 May 2024 04:55:00 +1000 Subject: [PATCH 5/8] Revert "Add %k, %l format specifiers" This reverts commit 2627fa5870bb2f7ec973a4f16b2c3552bf7dca2d. --- include/fmt/chrono.h | 12 ------------ test/chrono-test.cc | 4 ---- 2 files changed, 16 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 1927f3271696..aac422d162a3 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -819,12 +819,6 @@ FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, case 'I': handler.on_12_hour(numeric_system::standard, pad); break; - case 'k': - handler.on_24_hour(numeric_system::standard, pad_type::space); - break; - case 'l': - handler.on_12_hour(numeric_system::standard, pad_type::space); - break; case 'M': handler.on_minute(numeric_system::standard, pad); break; @@ -942,12 +936,6 @@ FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, case 'M': handler.on_minute(numeric_system::alternative, pad); break; - case 'k': - handler.on_24_hour(numeric_system::alternative, pad_type::space); - break; - case 'l': - handler.on_12_hour(numeric_system::alternative, pad_type::space); - break; case 'S': handler.on_second(numeric_system::alternative, pad); break; diff --git a/test/chrono-test.cc b/test/chrono-test.cc index a38bccca6ad1..0a70210d88de 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -980,8 +980,6 @@ TEST(chrono_test, glibc_extensions) { EXPECT_EQ(fmt::format("{:%0OI,%0OH,%0OM,%0OS}", d), "01,01,02,03"); EXPECT_EQ(fmt::format("{:%_OI,%_OH,%_OM,%_OS}", d), " 1, 1, 2, 3"); EXPECT_EQ(fmt::format("{:%-OI,%-OH,%-OM,%-OS}", d), "1,1,2,3"); - - EXPECT_EQ(fmt::format("{:%k,%l}", d), " 1, 1"); } { @@ -995,8 +993,6 @@ TEST(chrono_test, glibc_extensions) { EXPECT_EQ(fmt::format("{:%0OI,%0OH,%0OM,%0OS}", tm), "01,01,02,03"); EXPECT_EQ(fmt::format("{:%_OI,%_OH,%_OM,%_OS}", tm), " 1, 1, 2, 3"); EXPECT_EQ(fmt::format("{:%-OI,%-OH,%-OM,%-OS}", tm), "1,1,2,3"); - - EXPECT_EQ(fmt::format("{:%k,%l}", tm), " 1, 1"); } { From da4eed6d54c6c39b1c0323b923705774bada6fd0 Mon Sep 17 00:00:00 2001 From: Zaheen Jamil Date: Tue, 28 May 2024 06:20:05 +1000 Subject: [PATCH 6/8] Documentation --- doc/syntax.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/doc/syntax.rst b/doc/syntax.rst index 16326c28d30d..d1e8078b3439 100644 --- a/doc/syntax.rst +++ b/doc/syntax.rst @@ -318,9 +318,10 @@ Format specifications for chrono duration and time point types as well as .. productionlist:: sf chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`] chrono_specs: [`chrono_specs`] `conversion_spec` | `chrono_specs` `literal_char` - conversion_spec: "%" [`modifier`] `chrono_type` + conversion_spec: "%" [`padding_modifier`] [`locale_modifier`] `chrono_type` literal_char: - modifier: "E" | "O" + locale_modifier: "E" | "O" + padding_modifier: "E" | "O" chrono_type: "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "F" | : "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" | "n" | "p" | : "q" | "Q" | "r" | "R" | "S" | "t" | "T" | "u" | "U" | "V" | @@ -483,6 +484,21 @@ The available presentation types (*chrono_type*) are: Specifiers that have a calendaric component such as ``'d'`` (the day of month) are valid only for ``std::tm`` and time points but not durations. +The available padding modifiers (*padding_modifier*) are: + ++---------+--------------------------------------------------------------------+ +| Type | Meaning | ++=========+====================================================================+ +| ``'-'`` | Do not pad the field | ++---------+--------------------------------------------------------------------+ +| ``'_'`` | Pad with spaces | ++---------+--------------------------------------------------------------------+ +| ``'0'`` | Pad wish zeros | ++---------+--------------------------------------------------------------------+ + +Currently, these modifiers are only supported for the ``'H', 'I', 'M', 'S', 'U', 'V'`` +and ``'W'`` presentation types. + .. range-specs: Range Format Specifications From a917a6bd66d383a7ded9ceccccb34575082851f2 Mon Sep 17 00:00:00 2001 From: Zaheen Jamil Date: Tue, 28 May 2024 06:30:11 +1000 Subject: [PATCH 7/8] Updated doc based on strftime instead of date --- doc/syntax.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/syntax.rst b/doc/syntax.rst index d1e8078b3439..604780d2c638 100644 --- a/doc/syntax.rst +++ b/doc/syntax.rst @@ -489,11 +489,11 @@ The available padding modifiers (*padding_modifier*) are: +---------+--------------------------------------------------------------------+ | Type | Meaning | +=========+====================================================================+ -| ``'-'`` | Do not pad the field | +| ``'-'`` | Pad a numeric result with spaces. | +---------+--------------------------------------------------------------------+ -| ``'_'`` | Pad with spaces | +| ``'_'`` | Do not pad a numeric result string. | +---------+--------------------------------------------------------------------+ -| ``'0'`` | Pad wish zeros | +| ``'0'`` | Pad a numeric result string with zeros. | +---------+--------------------------------------------------------------------+ Currently, these modifiers are only supported for the ``'H', 'I', 'M', 'S', 'U', 'V'`` From f7507ab937080337d47e6e7e59c6c2d1c6d5fd1f Mon Sep 17 00:00:00 2001 From: Zaheen Jamil Date: Wed, 29 May 2024 20:52:46 +1000 Subject: [PATCH 8/8] Fixed typo in docs --- doc/syntax.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/syntax.rst b/doc/syntax.rst index 604780d2c638..d60815ea9eac 100644 --- a/doc/syntax.rst +++ b/doc/syntax.rst @@ -320,8 +320,8 @@ Format specifications for chrono duration and time point types as well as chrono_specs: [`chrono_specs`] `conversion_spec` | `chrono_specs` `literal_char` conversion_spec: "%" [`padding_modifier`] [`locale_modifier`] `chrono_type` literal_char: + padding_modifier: "-" | "_" | "0" locale_modifier: "E" | "O" - padding_modifier: "E" | "O" chrono_type: "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "F" | : "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" | "n" | "p" | : "q" | "Q" | "r" | "R" | "S" | "t" | "T" | "u" | "U" | "V" |