diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index dd003202..80cbe697 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -8,14 +8,14 @@ #ifndef FMT_CHRONO_H_ #define FMT_CHRONO_H_ -#include "format.h" -#include "locale.h" - #include #include #include #include +#include "format.h" +#include "locale.h" + FMT_BEGIN_NAMESPACE // Enable safe chrono durations, unless explicitly disabled. @@ -495,12 +495,12 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, handler.on_text(ptr - 1, ptr); break; case 'n': { - const char newline[] = "\n"; + const Char newline[]{'\n', 0}; handler.on_text(newline, newline + 1); break; } case 't': { - const char tab[] = "\t"; + const Char tab[]{'\t', 0}; handler.on_text(tab, tab + 1); break; } @@ -759,18 +759,30 @@ inline std::chrono::duration get_milliseconds( return std::chrono::duration(static_cast(ms)); } -template +template OutputIt format_duration_value(OutputIt out, Rep val, int precision) { - if (precision >= 0) return format_to(out, "{:.{}f}", val, precision); - return format_to(out, std::is_floating_point::value ? "{:g}" : "{}", + const Char pr_f[]{'{', ':', '.', '{', '}', 'f', '}', 0}; + if (precision >= 0) return format_to(out, pr_f, val, precision); + const Char fp_f[]{'{', ':', 'g', '}', 0}; + const Char format[]{'{', '}', 0}; + return format_to(out, std::is_floating_point::value ? fp_f : format, val); } -template +template OutputIt format_duration_unit(OutputIt out) { - if (const char* unit = get_units()) return format_to(out, "{}", unit); - if (Period::den == 1) return format_to(out, "[{}]s", Period::num); - return format_to(out, "[{}/{}]s", Period::num, Period::den); + if (const char* unit = get_units()) { + string_view s(unit); + if (const_check(std::is_same())) { + utf8_to_utf16 u(s); + return std::copy(u.c_str(), u.c_str() + u.size(), out); + } + return std::copy(s.begin(), s.end(), out); + } + const Char num_f[]{'[', '{', '}', ']', 's', 0}; + if (Period::den == 1) return format_to(out, num_f, Period::num); + const Char num_def_f[]{'[', '{', '}', '/', '{', '}', ']', 's', 0}; + return format_to(out, num_def_f, Period::num, Period::den); } template (); auto& facet = std::use_facet>(locale); std::basic_ostringstream os; os.imbue(locale); - facet.put(os, os, ' ', &time, format, format + std::strlen(format)); + facet.put(os, os, ' ', &time, format, modifier); auto str = os.str(); std::copy(str.begin(), str.end(), out); } @@ -907,7 +919,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(hour(), 2); auto time = tm(); time.tm_hour = to_nonnegative_int(hour(), 24); - format_localized(time, "%OH"); + format_localized(time, 'H', 'O'); } void on_12_hour(numeric_system ns) { @@ -916,7 +928,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(hour12(), 2); auto time = tm(); time.tm_hour = to_nonnegative_int(hour12(), 12); - format_localized(time, "%OI"); + format_localized(time, 'I', 'O'); } void on_minute(numeric_system ns) { @@ -925,7 +937,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(minute(), 2); auto time = tm(); time.tm_min = to_nonnegative_int(minute(), 60); - format_localized(time, "%OM"); + format_localized(time, 'M', 'O'); } void on_second(numeric_system ns) { @@ -950,13 +962,12 @@ struct chrono_formatter { } auto time = tm(); time.tm_sec = to_nonnegative_int(second(), 60); - format_localized(time, "%OS"); + format_localized(time, 'S', 'O'); } void on_12_hour_time() { if (handle_nan_inf()) return; - - format_localized(time(), "%r"); + format_localized(time(), 'r'); } void on_24_hour_time() { @@ -980,16 +991,18 @@ struct chrono_formatter { void on_am_pm() { if (handle_nan_inf()) return; - format_localized(time(), "%p"); + format_localized(time(), 'p'); } void on_duration_value() { if (handle_nan_inf()) return; write_sign(); - out = format_duration_value(out, val, precision); + out = format_duration_value(out, val, precision); } - void on_duration_unit() { out = format_duration_unit(out); } + void on_duration_unit() { + out = format_duration_unit(out); + } }; } // namespace internal @@ -1088,8 +1101,8 @@ struct formatter, Char> { internal::handle_dynamic_spec( precision, precision_ref, ctx); if (begin == end || *begin == '}') { - out = internal::format_duration_value(out, d.count(), precision); - internal::format_duration_unit(out); + out = internal::format_duration_value(out, d.count(), precision); + internal::format_duration_unit(out); } else { internal::chrono_formatter f( ctx, out, d); diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 04b5f2fa..828a8aee 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -145,6 +145,48 @@ TEST(ChronoTest, FormatDefault) { fmt::format("{}", std::chrono::duration>(42))); } +TEST(ChronoTest, FormatWide) { + EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42))); + EXPECT_EQ(L"42as", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42fs", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42ps", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42ns", fmt::format(L"{}", std::chrono::nanoseconds(42))); + EXPECT_EQ(L"42\u00B5s", fmt::format(L"{}", std::chrono::microseconds(42))); + EXPECT_EQ(L"42ms", fmt::format(L"{}", std::chrono::milliseconds(42))); + EXPECT_EQ(L"42cs", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42ds", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42))); + EXPECT_EQ(L"42das", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42hs", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42ks", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42Ms", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42Gs", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42Ts", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42Ps", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42Es", + fmt::format(L"{}", std::chrono::duration(42))); + EXPECT_EQ(L"42m", fmt::format(L"{}", std::chrono::minutes(42))); + EXPECT_EQ(L"42h", fmt::format(L"{}", std::chrono::hours(42))); + EXPECT_EQ( + L"42[15]s", + fmt::format(L"{}", std::chrono::duration>(42))); + EXPECT_EQ( + L"42[15/4]s", + fmt::format(L"{}", std::chrono::duration>(42))); +} + TEST(ChronoTest, Align) { auto s = std::chrono::seconds(42); EXPECT_EQ("42s ", fmt::format("{:5}", s));