Fix a few chrono formatting corner cases (#1178)

This commit is contained in:
Victor Zverovich 2019-05-29 18:02:26 -07:00
parent e5512c5d57
commit 30bce6c14c
2 changed files with 36 additions and 16 deletions

View File

@ -419,13 +419,10 @@ inline std::chrono::duration<Rep, std::milli> get_milliseconds(
}
template <typename Rep, typename OutputIt>
OutputIt static format_chrono_duration_value(OutputIt out, Rep val,
int precision) {
if (precision < 0) {
return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
val);
}
return format_to(out, "{:.{}f}", val, precision);
OutputIt format_chrono_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<Rep>::value ? "{:g}" : "{}",
val);
}
template <typename Period, typename OutputIt>
@ -441,20 +438,20 @@ struct chrono_formatter {
FormatContext& context;
OutputIt out;
int precision;
Rep val;
typedef std::chrono::duration<Rep> seconds;
typedef typename std::conditional<std::is_integral<Rep>::value &&
sizeof(Rep) < sizeof(int),
int, Rep>::type rep;
rep val;
typedef std::chrono::duration<rep> seconds;
seconds s;
typedef std::chrono::duration<Rep, std::milli> milliseconds;
typedef std::chrono::duration<rep, std::milli> milliseconds;
typedef typename FormatContext::char_type char_type;
explicit chrono_formatter(FormatContext& ctx, OutputIt o,
std::chrono::duration<Rep, Period> d)
: context(ctx), out(o), val(d.count()) {
if (d.count() < 0) {
d = -d;
*out++ = '-';
}
if (d.count() < 0) d = -d;
s = std::chrono::duration_cast<seconds>(d);
}
@ -476,7 +473,15 @@ struct chrono_formatter {
return time;
}
void write_sign() {
if (val < 0) {
*out++ = '-';
val = -val;
}
}
void write(Rep value, int width) {
write_sign();
if (isnan(value)) return write_nan();
typedef typename int_traits<int>::main_type main_type;
main_type n = to_unsigned(to_int(value));
@ -570,6 +575,7 @@ struct chrono_formatter {
void on_am_pm() { format_localized(time(), "%p"); }
void on_duration_value() {
write_sign();
out = format_chrono_duration_value(out, val, precision);
}

View File

@ -306,12 +306,22 @@ TEST(ChronoTest, InvalidColons) {
fmt::format_error);
}
TEST(ChronoTest, NegativeDuration) {
EXPECT_EQ("-12345", fmt::format("{:%Q}", std::chrono::seconds(-12345)));
EXPECT_EQ("-03:25:45",
fmt::format("{:%H:%M:%S}", std::chrono::seconds(-12345)));
EXPECT_EQ("-00:01",
fmt::format("{:%M:%S}", std::chrono::duration<double>(-1)));
EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(-12345)));
EXPECT_EQ("-00.127",
fmt::format("{:%S}",
std::chrono::duration<signed char, std::milli>{-127}));
}
TEST(ChronoTest, SpecialDurations) {
EXPECT_EQ(
"40.",
fmt::format("{:%S}", std::chrono::duration<double>(1e20)).substr(0, 3));
EXPECT_EQ("-00:01",
fmt::format("{:%M:%S}", std::chrono::duration<double>(-1)));
auto nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ(
"nan nan nan nan.nan nan:nan nan",
@ -322,6 +332,10 @@ TEST(ChronoTest, SpecialDurations) {
"1Es");
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)),
"1as");
EXPECT_EQ(fmt::format("{:%R}", std::chrono::duration<char, std::mega>{2}),
"03:33");
EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
"03:33:20");
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR