Fix width and alignment for calendar types (#4935)

This commit is contained in:
IfkumRfnl 2026-09-11 19:22:02 +04:00 committed by GitHub
parent 56fcd0b945
commit 2012961e3e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 59 additions and 12 deletions

View File

@ -1908,11 +1908,8 @@ struct formatter<weekday, Char> : private formatter<std::tm, Char> {
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
this->set_format(detail::string_literal<Char, '%', 'a'>());
auto it = ctx.begin(), end = ctx.end();
if (it != end && *it == 'L') {
++it;
this->set_localized();
}
use_tm_formatter_ = it != end && *it != '}';
return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
}
@ -1922,7 +1919,7 @@ struct formatter<weekday, Char> : private formatter<std::tm, Char> {
auto time = std::tm();
time.tm_wday = static_cast<int>(wd.c_encoding());
if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
detail::get_locale loc(this->localized(), ctx.locale());
detail::get_locale loc(false, ctx.locale());
auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
w.on_abbr_weekday();
return w.out();
@ -1936,6 +1933,7 @@ struct formatter<day, Char> : private formatter<std::tm, Char> {
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
this->set_format(detail::string_literal<Char, '%', 'd'>());
auto it = ctx.begin(), end = ctx.end();
use_tm_formatter_ = it != end && *it != '}';
return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
@ -1960,11 +1958,8 @@ struct formatter<month, Char> : private formatter<std::tm, Char> {
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
this->set_format(detail::string_literal<Char, '%', 'b'>());
auto it = ctx.begin(), end = ctx.end();
if (it != end && *it == 'L') {
++it;
this->set_localized();
}
use_tm_formatter_ = it != end && *it != '}';
return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
}
@ -1974,7 +1969,7 @@ struct formatter<month, Char> : private formatter<std::tm, Char> {
auto time = std::tm();
time.tm_mon = static_cast<int>(static_cast<unsigned>(m)) - 1;
if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
detail::get_locale loc(this->localized(), ctx.locale());
detail::get_locale loc(false, ctx.locale());
auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
w.on_abbr_month();
return w.out();
@ -1988,6 +1983,7 @@ struct formatter<year, Char> : private formatter<std::tm, Char> {
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
this->set_format(detail::string_literal<Char, '%', 'Y'>());
auto it = ctx.begin(), end = ctx.end();
use_tm_formatter_ = it != end && *it != '}';
return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
@ -2012,6 +2008,7 @@ struct formatter<year_month_day, Char> : private formatter<std::tm, Char> {
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
this->set_format(detail::string_literal<Char, '%', 'F'>());
auto it = ctx.begin(), end = ctx.end();
use_tm_formatter_ = it != end && *it != '}';
return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
@ -2106,8 +2103,7 @@ template <typename Char> struct formatter<std::tm, Char> {
detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>();
protected:
auto localized() const -> bool { return specs_.localized(); }
FMT_CONSTEXPR void set_localized() { specs_.set_localized(); }
FMT_CONSTEXPR void set_format(basic_string_view<Char> fmt) { fmt_ = fmt; }
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx, bool has_timezone)
-> const Char* {

View File

@ -994,6 +994,57 @@ TEST(chrono_test, out_of_range) {
EXPECT_THROW((void)fmt::format("{:%j}", fd), fmt::format_error);
}
template <typename T>
void check_calendar_padding(T value, const char* expected,
const char* chrono_format) {
EXPECT_EQ(expected, fmt::format("{}", value));
EXPECT_EQ(expected, fmt::format("{:}", value));
EXPECT_EQ(fmt::format("{:15}", expected), fmt::format("{:15}", value));
EXPECT_EQ(fmt::format("{:<15}", expected), fmt::format("{:<15}", value));
EXPECT_EQ(fmt::format("{:>15}", expected), fmt::format("{:>15}", value));
EXPECT_EQ(fmt::format("{:*^15}", expected), fmt::format("{:*^15}", value));
EXPECT_EQ(fmt::format("{:%>15}", expected), fmt::format("{:%>15}", value));
EXPECT_EQ(fmt::format("{:L>15}", expected), fmt::format("{:L>15}", value));
EXPECT_EQ(fmt::format("{:>15}", expected), fmt::format("{:>{}}", value, 15));
EXPECT_EQ(expected, fmt::format("{:1}", value));
auto explicit_format = fmt::format("{{:*^15{}}}", chrono_format);
auto unpadded_format = fmt::format("{{:{}}}", chrono_format);
EXPECT_EQ(fmt::format("{:*^15}",
fmt::format(runtime(unpadded_format), value)),
fmt::format(runtime(explicit_format), value));
EXPECT_THROW((void)fmt::format(runtime("{:>{}}"), value, -1),
fmt::format_error);
}
TEST(chrono_test, calendar_padding) {
check_calendar_padding(fmt::day(5), "05", "%d");
check_calendar_padding(fmt::month(1), "Jan", "%B");
check_calendar_padding(fmt::year(2024), "2024", "%y");
check_calendar_padding(fmt::weekday(6), "Sat", "%A");
check_calendar_padding(
fmt::year_month_day(fmt::year(2024), fmt::month(1), fmt::day(5)),
"2024-01-05", "%Y/%m/%d");
}
template <typename T> void check_localized_calendar_padding(T value) {
auto loc = get_locale("es_ES.UTF-8");
auto expected = fmt::format(loc, "{:L}", value);
EXPECT_EQ(fmt::format("{:*>15}", expected),
fmt::format(loc, "{:*>15L}", value));
EXPECT_EQ(fmt::format("{:>15}", expected),
fmt::format(loc, "{:>{}L}", value, 15));
}
TEST(chrono_test, localized_calendar_padding) {
check_localized_calendar_padding(fmt::month(1));
check_localized_calendar_padding(fmt::weekday(6));
auto loc = get_locale("es_ES.UTF-8");
EXPECT_EQ(fmt::format("{:>15}", fmt::format(loc, "{:L%B}", fmt::month(1))),
fmt::format(loc, "{:>15L%B}", fmt::month(1)));
EXPECT_EQ(fmt::format("{:>15}", fmt::format(loc, "{:L%A}", fmt::weekday(6))),
fmt::format(loc, "{:>15L%A}", fmt::weekday(6)));
}
TEST(chrono_test, year_month_day) {
auto loc = get_locale("es_ES.UTF-8");
std::locale::global(loc);