Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add glibc ext for day of month and week of year #3976

Merged
merged 10 commits into from
May 30, 2024
89 changes: 44 additions & 45 deletions include/fmt/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand All @@ -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;
Expand Down Expand Up @@ -907,19 +913,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);
Expand All @@ -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;
Expand Down Expand Up @@ -972,12 +984,11 @@ template <typename Derived> 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(); }
ZaheenJ marked this conversation as resolved.
Show resolved Hide resolved
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(); }
Expand Down Expand Up @@ -1015,12 +1026,11 @@ struct tm_format_checker : null_chrono_spec_handler<tm_format_checker> {
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) {}
Expand Down Expand Up @@ -1454,7 +1464,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_++ = ' ';
Expand Down Expand Up @@ -1541,24 +1551,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');
}

Expand All @@ -1572,20 +1582,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)
Expand Down Expand Up @@ -1933,11 +1933,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) {}
ZaheenJ marked this conversation as resolved.
Show resolved Hide resolved

void on_day_of_year() {
if (handle_nan_inf()) return;
Expand Down Expand Up @@ -2156,7 +2155,7 @@ struct formatter<day, Char> : private formatter<std::tm, Char> {
if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
detail::get_locale loc(false, ctx.locale());
auto w = detail::tm_writer<decltype(ctx.out()), Char>(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();
}
};
Expand Down
26 changes: 25 additions & 1 deletion test/chrono-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

{
Expand All @@ -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");
}

{
Expand All @@ -1004,12 +1008,32 @@ TEST(chrono_test, glibc_extensions) {
}

{
const auto d = std::chrono::duration<double>(3.14);
auto d = std::chrono::duration<double>(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) {
Expand Down
Loading