Use the same rep type for seconds to prevent overflow

This commit is contained in:
Victor Zverovich
2019-05-04 09:22:09 -07:00
parent 241414028d
commit 38a85502ed
2 changed files with 23 additions and 7 deletions

View File

@ -376,13 +376,24 @@ struct chrono_format_checker {
FMT_NORETURN void on_tz_name() { report_no_date(); } FMT_NORETURN void on_tz_name() { report_no_date(); }
}; };
template <typename Int> inline int to_int(Int value) { template <typename T> inline int to_int(T value) {
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() && FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
value <= (std::numeric_limits<int>::max)(), value <= (std::numeric_limits<int>::max)(),
"invalid value"); "invalid value");
return static_cast<int>(value); return static_cast<int>(value);
} }
template <typename T,
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
inline T mod(T x, int y) {
return x % y;
}
template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
inline T mod(T x, int y) {
return std::fmod(x, y);
}
template <typename Rep, typename OutputIt> template <typename Rep, typename OutputIt>
OutputIt static format_chrono_duration_value(OutputIt out, Rep val, OutputIt static format_chrono_duration_value(OutputIt out, Rep val,
int precision) { int precision) {
@ -410,8 +421,9 @@ struct chrono_formatter {
OutputIt out; OutputIt out;
int precision; int precision;
Rep val; 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;
std::chrono::seconds s;
milliseconds ms; milliseconds ms;
typedef typename FormatContext::char_type char_type; typedef typename FormatContext::char_type char_type;
@ -421,18 +433,18 @@ struct chrono_formatter {
: context(ctx), : context(ctx),
out(o), out(o),
val(d.count()), val(d.count()),
s(std::chrono::duration_cast<std::chrono::seconds>(d)), s(std::chrono::duration_cast<seconds>(d)),
ms(std::chrono::duration_cast<milliseconds>(d - s)) {} ms(std::chrono::duration_cast<milliseconds>(d - s)) {}
int hour() const { return to_int((s.count() / 3600) % 24); } int hour() const { return to_int(mod((s.count() / 3600), 24)); }
int hour12() const { int hour12() const {
auto hour = to_int((s.count() / 3600) % 12); auto hour = to_int(mod((s.count() / 3600), 12));
return hour > 0 ? hour : 12; return hour > 0 ? hour : 12;
} }
int minute() const { return to_int((s.count() / 60) % 60); } int minute() const { return to_int(mod((s.count() / 60), 60)); }
int second() const { return to_int(s.count() % 60); } int second() const { return to_int(mod(s.count(), 60)); }
std::tm time() const { std::tm time() const {
auto time = std::tm(); auto time = std::tm();

View File

@ -306,4 +306,8 @@ TEST(ChronoTest, InvalidColons) {
fmt::format_error); fmt::format_error);
} }
TEST(ChronoTest, LargeDuration) {
EXPECT_EQ("40", fmt::format("{:%S}", std::chrono::duration<double>(1e20)));
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR #endif // FMT_STATIC_THOUSANDS_SEPARATOR