mirror of
https://github.com/fmtlib/fmt.git
synced 2024-10-02 04:52:03 +00:00
Fix a few chrono formatting corner cases (#1178)
This commit is contained in:
parent
e5512c5d57
commit
30bce6c14c
@ -419,13 +419,10 @@ inline std::chrono::duration<Rep, std::milli> get_milliseconds(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Rep, typename OutputIt>
|
template <typename Rep, typename OutputIt>
|
||||||
OutputIt static format_chrono_duration_value(OutputIt out, Rep val,
|
OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) {
|
||||||
int precision) {
|
if (precision >= 0) return format_to(out, "{:.{}f}", val, precision);
|
||||||
if (precision < 0) {
|
return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
|
||||||
return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
|
val);
|
||||||
val);
|
|
||||||
}
|
|
||||||
return format_to(out, "{:.{}f}", val, precision);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Period, typename OutputIt>
|
template <typename Period, typename OutputIt>
|
||||||
@ -441,20 +438,20 @@ struct chrono_formatter {
|
|||||||
FormatContext& context;
|
FormatContext& context;
|
||||||
OutputIt out;
|
OutputIt out;
|
||||||
int precision;
|
int precision;
|
||||||
Rep val;
|
typedef typename std::conditional<std::is_integral<Rep>::value &&
|
||||||
typedef std::chrono::duration<Rep> seconds;
|
sizeof(Rep) < sizeof(int),
|
||||||
|
int, Rep>::type rep;
|
||||||
|
rep val;
|
||||||
|
typedef std::chrono::duration<rep> seconds;
|
||||||
seconds s;
|
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;
|
typedef typename FormatContext::char_type char_type;
|
||||||
|
|
||||||
explicit chrono_formatter(FormatContext& ctx, OutputIt o,
|
explicit chrono_formatter(FormatContext& ctx, OutputIt o,
|
||||||
std::chrono::duration<Rep, Period> d)
|
std::chrono::duration<Rep, Period> d)
|
||||||
: context(ctx), out(o), val(d.count()) {
|
: context(ctx), out(o), val(d.count()) {
|
||||||
if (d.count() < 0) {
|
if (d.count() < 0) d = -d;
|
||||||
d = -d;
|
|
||||||
*out++ = '-';
|
|
||||||
}
|
|
||||||
s = std::chrono::duration_cast<seconds>(d);
|
s = std::chrono::duration_cast<seconds>(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +473,15 @@ struct chrono_formatter {
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write_sign() {
|
||||||
|
if (val < 0) {
|
||||||
|
*out++ = '-';
|
||||||
|
val = -val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void write(Rep value, int width) {
|
void write(Rep value, int width) {
|
||||||
|
write_sign();
|
||||||
if (isnan(value)) return write_nan();
|
if (isnan(value)) return write_nan();
|
||||||
typedef typename int_traits<int>::main_type main_type;
|
typedef typename int_traits<int>::main_type main_type;
|
||||||
main_type n = to_unsigned(to_int(value));
|
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_am_pm() { format_localized(time(), "%p"); }
|
||||||
|
|
||||||
void on_duration_value() {
|
void on_duration_value() {
|
||||||
|
write_sign();
|
||||||
out = format_chrono_duration_value(out, val, precision);
|
out = format_chrono_duration_value(out, val, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,12 +306,22 @@ TEST(ChronoTest, InvalidColons) {
|
|||||||
fmt::format_error);
|
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) {
|
TEST(ChronoTest, SpecialDurations) {
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
"40.",
|
"40.",
|
||||||
fmt::format("{:%S}", std::chrono::duration<double>(1e20)).substr(0, 3));
|
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();
|
auto nan = std::numeric_limits<double>::quiet_NaN();
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
"nan nan nan nan.nan nan:nan nan",
|
"nan nan nan nan.nan nan:nan nan",
|
||||||
@ -322,6 +332,10 @@ TEST(ChronoTest, SpecialDurations) {
|
|||||||
"1Es");
|
"1Es");
|
||||||
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)),
|
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)),
|
||||||
"1as");
|
"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
|
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
Loading…
Reference in New Issue
Block a user