mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 02:37:36 +02:00
Improve year formatter
This commit is contained in:
committed by
Victor Zverovich
parent
b04601b918
commit
cde44ddb72
@ -1406,12 +1406,29 @@ template <typename FormatContext, typename OutputIt> struct tm_formatter {
|
|||||||
OutputIt out;
|
OutputIt out;
|
||||||
const std::tm& tm;
|
const std::tm& tm;
|
||||||
|
|
||||||
auto tm_year() const -> decltype(tm.tm_year) { return 1900 + tm.tm_year; }
|
auto tm_year() const -> int { return 1900 + tm.tm_year; }
|
||||||
|
// POSIX and the C Standard are unclear or inconsistent about what %C and %y
|
||||||
|
// do if the year is negative or exceeds 9999. Use the convention that %C
|
||||||
|
// concatenated with %y yields the same output as %Y, and that %Y contains at
|
||||||
|
// least 4 bytes, with more only if necessary.
|
||||||
|
struct split_year {
|
||||||
|
int upper;
|
||||||
|
int lower;
|
||||||
|
};
|
||||||
|
auto tm_split_year() const -> split_year {
|
||||||
|
auto year = tm_year();
|
||||||
|
auto q = year / 100;
|
||||||
|
auto r = year % 100;
|
||||||
|
if (r < 0) {
|
||||||
|
// r in [0, 99]
|
||||||
|
r = -r;
|
||||||
|
}
|
||||||
|
return {q, r};
|
||||||
|
}
|
||||||
auto tm_hour12() const -> decltype(tm.tm_hour) {
|
auto tm_hour12() const -> decltype(tm.tm_hour) {
|
||||||
auto hour = tm.tm_hour % 12;
|
auto hour = tm.tm_hour % 12;
|
||||||
return hour == 0 ? 12 : hour;
|
return hour == 0 ? 12 : hour;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr char digits1(size_t value) {
|
static constexpr char digits1(size_t value) {
|
||||||
return detail::digits2(value)[1];
|
return detail::digits2(value)[1];
|
||||||
}
|
}
|
||||||
@ -1478,12 +1495,11 @@ template <typename FormatContext, typename OutputIt> struct tm_formatter {
|
|||||||
format_localized('X', ns == numeric_system::standard ? '\0' : 'E');
|
format_localized('X', ns == numeric_system::standard ? '\0' : 'E');
|
||||||
}
|
}
|
||||||
void on_us_date() {
|
void on_us_date() {
|
||||||
auto year = tm_year();
|
|
||||||
char buf[8];
|
char buf[8];
|
||||||
detail::write_digit2_separated(
|
detail::write_digit2_separated(buf, detail::to_unsigned(tm.tm_mon + 1),
|
||||||
buf, detail::to_unsigned(tm.tm_mon + 1),
|
detail::to_unsigned(tm.tm_mday),
|
||||||
detail::to_unsigned(tm.tm_mday),
|
detail::to_unsigned(tm_split_year().lower),
|
||||||
detail::to_unsigned((year < 0 ? -year : year) % 100), '/');
|
'/');
|
||||||
out = std::copy_n(buf, sizeof(buf), out);
|
out = std::copy_n(buf, sizeof(buf), out);
|
||||||
}
|
}
|
||||||
void on_iso_date() {
|
void on_iso_date() {
|
||||||
@ -1513,9 +1529,8 @@ template <typename FormatContext, typename OutputIt> struct tm_formatter {
|
|||||||
}
|
}
|
||||||
void on_last2_year(numeric_system ns) {
|
void on_last2_year(numeric_system ns) {
|
||||||
if (ns == numeric_system::standard) {
|
if (ns == numeric_system::standard) {
|
||||||
// TODO: Negative years?
|
out = std::copy_n(
|
||||||
out = std::copy_n(detail::digits2(detail::to_unsigned(tm_year() % 100)),
|
detail::digits2(detail::to_unsigned(tm_split_year().lower)), 2, out);
|
||||||
2, out);
|
|
||||||
} else {
|
} else {
|
||||||
format_localized('y', 'O');
|
format_localized('y', 'O');
|
||||||
}
|
}
|
||||||
@ -1523,13 +1538,13 @@ template <typename FormatContext, typename OutputIt> struct tm_formatter {
|
|||||||
void on_offset_year() { format_localized('y', 'E'); }
|
void on_offset_year() { format_localized('y', 'E'); }
|
||||||
void on_base_year(numeric_system ns) {
|
void on_base_year(numeric_system ns) {
|
||||||
if (ns == numeric_system::standard) {
|
if (ns == numeric_system::standard) {
|
||||||
// TODO: Negative years?
|
auto split = tm_split_year();
|
||||||
auto format_specs = basic_format_specs<char_type>();
|
if (split.upper >= 0 && split.upper < 100) {
|
||||||
format_specs.width = 2;
|
out = std::copy_n(detail::digits2(detail::to_unsigned(split.upper)), 2,
|
||||||
format_specs.align = align::numeric;
|
out);
|
||||||
format_specs.fill[0] = char_type('0');
|
} else {
|
||||||
auto year = tm_year();
|
out = detail::write<char_type>(out, split.upper);
|
||||||
out = detail::write(out, year / 100, format_specs, {});
|
}
|
||||||
} else {
|
} else {
|
||||||
format_localized('C', 'E');
|
format_localized('C', 'E');
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ TEST(chrono_test, format_tm) {
|
|||||||
"The date is 2016-04-25 11:22:33.");
|
"The date is 2016-04-25 11:22:33.");
|
||||||
EXPECT_EQ(fmt::format("{:%Y}", tm), "2016");
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "2016");
|
||||||
EXPECT_EQ(fmt::format("{:%C}", tm), "20");
|
EXPECT_EQ(fmt::format("{:%C}", tm), "20");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
|
||||||
EXPECT_EQ(fmt::format("{:%e}", tm), "25");
|
EXPECT_EQ(fmt::format("{:%e}", tm), "25");
|
||||||
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/16");
|
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/16");
|
||||||
EXPECT_EQ(fmt::format("{:%F}", tm), "2016-04-25");
|
EXPECT_EQ(fmt::format("{:%F}", tm), "2016-04-25");
|
||||||
@ -74,6 +75,7 @@ TEST(chrono_test, format_tm_future) {
|
|||||||
"The date is 12345-04-25 11:22:33.");
|
"The date is 12345-04-25 11:22:33.");
|
||||||
EXPECT_EQ(fmt::format("{:%Y}", tm), "12345");
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "12345");
|
||||||
EXPECT_EQ(fmt::format("{:%C}", tm), "123");
|
EXPECT_EQ(fmt::format("{:%C}", tm), "123");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
|
||||||
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/45");
|
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/45");
|
||||||
EXPECT_EQ(fmt::format("{:%F}", tm), "12345-04-25");
|
EXPECT_EQ(fmt::format("{:%F}", tm), "12345-04-25");
|
||||||
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
|
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
|
||||||
@ -91,14 +93,15 @@ TEST(chrono_test, format_tm_past) {
|
|||||||
"The date is -101-04-25 11:22:33.");
|
"The date is -101-04-25 11:22:33.");
|
||||||
EXPECT_EQ(fmt::format("{:%Y}", tm), "-101");
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "-101");
|
||||||
|
|
||||||
// macOS %C - "-1"
|
// macOS %C - "-1"
|
||||||
// Linux %C - "-2"
|
// Linux %C - "-2"
|
||||||
// Simple impl %C - "-1"
|
// fmt %C - "-1"
|
||||||
EXPECT_EQ(fmt::format("{:%C}", tm), "-1");
|
EXPECT_EQ(fmt::format("{:%C}", tm), "-1");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
|
||||||
|
|
||||||
// macOS %D - "04/25/01" (%y)
|
// macOS %D - "04/25/01" (%y)
|
||||||
// Linux %D - "04/25/99" (%y)
|
// Linux %D - "04/25/99" (%y)
|
||||||
// Simple impl %D - "04/25/01" (%y)
|
// fmt %D - "04/25/01" (%y)
|
||||||
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/01");
|
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/01");
|
||||||
|
|
||||||
EXPECT_EQ(fmt::format("{:%F}", tm), "-101-04-25");
|
EXPECT_EQ(fmt::format("{:%F}", tm), "-101-04-25");
|
||||||
|
Reference in New Issue
Block a user