Fix handling of nan durations

This commit is contained in:
Victor Zverovich 2019-05-05 08:34:54 -07:00
parent c1d430e61a
commit ca978b3d21
2 changed files with 38 additions and 21 deletions

View File

@ -376,9 +376,20 @@ struct chrono_format_checker {
FMT_NORETURN void on_tz_name() { report_no_date(); }
};
template <typename T,
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
inline bool isnan(T) {
return false;
}
template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
inline bool isnan(T value) {
return std::isnan(value);
}
template <typename T> inline int to_int(T value) {
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
value <= (std::numeric_limits<int>::max)(),
FMT_ASSERT(isnan(value) || (value >= (std::numeric_limits<int>::min)() &&
value <= (std::numeric_limits<int>::max)()),
"invalid value");
return static_cast<int>(value);
}
@ -439,33 +450,37 @@ struct chrono_formatter {
ms = std::chrono::duration_cast<milliseconds>(d - s);
}
int hour() const { return to_int(mod((s.count() / 3600), 24)); }
Rep hour() const { return mod((s.count() / 3600), 24); }
int hour12() const {
auto hour = to_int(mod((s.count() / 3600), 12));
return hour > 0 ? hour : 12;
Rep hour12() const {
Rep hour = mod((s.count() / 3600), 12);
return hour <= 0 ? 12 : hour;
}
int minute() const { return to_int(mod((s.count() / 60), 60)); }
int second() const { return to_int(mod(s.count(), 60)); }
Rep minute() const { return mod((s.count() / 60), 60); }
Rep second() const { return mod(s.count(), 60); }
std::tm time() const {
auto time = std::tm();
time.tm_hour = hour();
time.tm_min = minute();
time.tm_sec = second();
time.tm_hour = to_int(hour());
time.tm_min = to_int(minute());
time.tm_sec = to_int(second());
return time;
}
void write(int value, int width) {
void write(Rep value, int width) {
if (isnan(value)) return write_nan();
typedef typename int_traits<int>::main_type main_type;
main_type n = to_unsigned(value);
main_type n = to_unsigned(to_int(value));
int num_digits = internal::count_digits(n);
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
out = format_decimal<char_type>(out, n, num_digits);
}
void write_nan() { std::copy_n("nan", 3, out); }
void format_localized(const tm& time, const char* format) {
if (isnan(val)) return write_nan();
auto locale = context.locale().template get<std::locale>();
auto& facet = std::use_facet<std::time_put<char_type>>(locale);
std::basic_ostringstream<char_type> os;
@ -497,14 +512,14 @@ struct chrono_formatter {
void on_24_hour(numeric_system ns) {
if (ns == numeric_system::standard) return write(hour(), 2);
auto time = tm();
time.tm_hour = hour();
time.tm_hour = to_int(hour());
format_localized(time, "%OH");
}
void on_12_hour(numeric_system ns) {
if (ns == numeric_system::standard) return write(hour12(), 2);
auto time = tm();
time.tm_hour = hour();
time.tm_hour = hour12();
format_localized(time, "%OI");
}
@ -520,7 +535,7 @@ struct chrono_formatter {
write(second(), 2);
if (ms != std::chrono::milliseconds(0)) {
*out++ = '.';
write(to_int(ms.count()), 3);
write(ms.count(), 3);
}
return;
}

View File

@ -306,12 +306,14 @@ TEST(ChronoTest, InvalidColons) {
fmt::format_error);
}
TEST(ChronoTest, LargeDuration) {
TEST(ChronoTest, SpecialDurations) {
EXPECT_EQ("40", fmt::format("{:%S}", std::chrono::duration<double>(1e20)));
}
TEST(ChronoTest, NegativeDuration) {
EXPECT_EQ("-00:01", fmt::format("{:%M:%S}", std::chrono::duration<double>(-1)));
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",
fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan)));
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR