From de5da509103aaa0e262135ceb7c13b4d4ace7358 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 11 May 2019 08:42:02 -0700 Subject: [PATCH] Fix formatting of extreme durations (#1154) --- include/fmt/chrono.h | 17 ++++++----------- include/fmt/format.h | 12 ++++-------- include/fmt/time.h | 4 ++-- test/chrono-test.cc | 4 ++++ 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 74d64ac9..06ced173 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -414,9 +414,8 @@ template < typename std::enable_if::value, int>::type = 0> inline std::chrono::duration get_milliseconds( std::chrono::duration d) { - auto ms = - std::chrono::duration_cast>(d); - return std::chrono::duration(mod(ms.count(), 1000)); + return std::chrono::duration( + mod(d.count() * Period::num / Period::den * 1000, 1000)); } template @@ -431,12 +430,9 @@ OutputIt static format_chrono_duration_value(OutputIt out, Rep val, template static OutputIt format_chrono_duration_unit(OutputIt out) { - if (const char* unit = get_units()) - return format_to(out, "{}", unit); - else if (Period::den == 1) - return format_to(out, "[{}]s", Period::num); - else - return format_to(out, "[{}/{}]s", Period::num, Period::den); + 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); } template seconds; seconds s; typedef std::chrono::duration milliseconds; - milliseconds ms; typedef typename FormatContext::char_type char_type; @@ -461,7 +456,6 @@ struct chrono_formatter { *out++ = '-'; } s = std::chrono::duration_cast(d); - ms = get_milliseconds(d); } Rep hour() const { return mod((s.count() / 3600), 24); } @@ -547,6 +541,7 @@ struct chrono_formatter { void on_second(numeric_system ns) { if (ns == numeric_system::standard) { write(second(), 2); + auto ms = get_milliseconds(std::chrono::duration(val)); if (ms != std::chrono::milliseconds(0)) { *out++ = '.'; write(ms.count(), 3); diff --git a/include/fmt/format.h b/include/fmt/format.h index c320abcf..5efbd2dc 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -251,7 +251,7 @@ namespace uintptr { struct uintptr_t { unsigned char value[sizeof(void*)]; }; -} +} // namespace uintptr using uintptr::uintptr_t; typedef std::numeric_limits numutil; @@ -1113,10 +1113,7 @@ FMT_CONSTEXPR unsigned basic_parse_context::next_arg_id() { namespace internal { namespace grisu_options { -enum { - fixed = 1, - grisu3 = 2 -}; +enum { fixed = 1, grisu3 = 2 }; } // Formats value using the Grisu algorithm: @@ -1190,8 +1187,7 @@ It grisu_prettify(const char* digits, int size, int exp, It it, if (!params.trailing_zeros) { // Remove trailing zeros. while (size > full_exp && digits[size - 1] == '0') --size; - if (size != full_exp) - *it++ = static_cast('.'); + if (size != full_exp) *it++ = static_cast('.'); return copy_str(digits + full_exp, digits + size, it); } *it++ = static_cast('.'); @@ -2877,7 +2873,7 @@ void basic_writer::write_double(T value, const format_specs& spec) { (spec.type != 'a' && spec.type != 'A' && spec.type != 'e' && spec.type != 'E') && internal::grisu_format(static_cast(value), buffer, - precision, options, exp); + precision, options, exp); if (!use_grisu) internal::sprintf_format(value, buffer, spec); if (handler.as_percentage) { diff --git a/include/fmt/time.h b/include/fmt/time.h index 80fe6e42..d15f9509 100644 --- a/include/fmt/time.h +++ b/include/fmt/time.h @@ -11,9 +11,9 @@ #include "chrono.h" #ifdef _MSC_VER -#pragma message("fmt/time.h is deprecated, use fmt/chrono.h instead") +# pragma message("fmt/time.h is deprecated, use fmt/chrono.h instead") #else -#warning fmt/time.h is deprecated, use fmt/chrono.h instead +# warning fmt/time.h is deprecated, use fmt/chrono.h instead #endif #endif // FMT_TIME_H_ diff --git a/test/chrono-test.cc b/test/chrono-test.cc index fbf49b52..2179e0e7 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -318,6 +318,10 @@ TEST(ChronoTest, SpecialDurations) { fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration(nan))); fmt::format("{:%S}", std::chrono::duration(1.79400457e+31f)); + EXPECT_EQ(fmt::format("{}", std::chrono::duration(1)), + "1Es"); + EXPECT_EQ(fmt::format("{}", std::chrono::duration(1)), + "1as"); } #endif // FMT_STATIC_THOUSANDS_SEPARATOR