mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Fix formatting of extreme durations (#1154)
This commit is contained in:
@ -414,9 +414,8 @@ template <
|
|||||||
typename std::enable_if<std::is_floating_point<Rep>::value, int>::type = 0>
|
typename std::enable_if<std::is_floating_point<Rep>::value, int>::type = 0>
|
||||||
inline std::chrono::duration<Rep, std::milli> get_milliseconds(
|
inline std::chrono::duration<Rep, std::milli> get_milliseconds(
|
||||||
std::chrono::duration<Rep, Period> d) {
|
std::chrono::duration<Rep, Period> d) {
|
||||||
auto ms =
|
return std::chrono::duration<Rep, std::milli>(
|
||||||
std::chrono::duration_cast<std::chrono::duration<Rep, std::milli>>(d);
|
mod(d.count() * Period::num / Period::den * 1000, 1000));
|
||||||
return std::chrono::duration<Rep, std::milli>(mod(ms.count(), 1000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Rep, typename OutputIt>
|
template <typename Rep, typename OutputIt>
|
||||||
@ -431,12 +430,9 @@ OutputIt static format_chrono_duration_value(OutputIt out, Rep val,
|
|||||||
|
|
||||||
template <typename Period, typename OutputIt>
|
template <typename Period, typename OutputIt>
|
||||||
static OutputIt format_chrono_duration_unit(OutputIt out) {
|
static OutputIt format_chrono_duration_unit(OutputIt out) {
|
||||||
if (const char* unit = get_units<Period>())
|
if (const char* unit = get_units<Period>()) return format_to(out, "{}", unit);
|
||||||
return format_to(out, "{}", unit);
|
if (Period::den == 1) return format_to(out, "[{}]s", Period::num);
|
||||||
else if (Period::den == 1)
|
return format_to(out, "[{}/{}]s", Period::num, Period::den);
|
||||||
return format_to(out, "[{}]s", Period::num);
|
|
||||||
else
|
|
||||||
return format_to(out, "[{}/{}]s", Period::num, Period::den);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext, typename OutputIt, typename Rep,
|
template <typename FormatContext, typename OutputIt, typename Rep,
|
||||||
@ -449,7 +445,6 @@ struct chrono_formatter {
|
|||||||
typedef std::chrono::duration<Rep> seconds;
|
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;
|
||||||
milliseconds ms;
|
|
||||||
|
|
||||||
typedef typename FormatContext::char_type char_type;
|
typedef typename FormatContext::char_type char_type;
|
||||||
|
|
||||||
@ -461,7 +456,6 @@ struct chrono_formatter {
|
|||||||
*out++ = '-';
|
*out++ = '-';
|
||||||
}
|
}
|
||||||
s = std::chrono::duration_cast<seconds>(d);
|
s = std::chrono::duration_cast<seconds>(d);
|
||||||
ms = get_milliseconds(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rep hour() const { return mod((s.count() / 3600), 24); }
|
Rep hour() const { return mod((s.count() / 3600), 24); }
|
||||||
@ -547,6 +541,7 @@ struct chrono_formatter {
|
|||||||
void on_second(numeric_system ns) {
|
void on_second(numeric_system ns) {
|
||||||
if (ns == numeric_system::standard) {
|
if (ns == numeric_system::standard) {
|
||||||
write(second(), 2);
|
write(second(), 2);
|
||||||
|
auto ms = get_milliseconds(std::chrono::duration<Rep, Period>(val));
|
||||||
if (ms != std::chrono::milliseconds(0)) {
|
if (ms != std::chrono::milliseconds(0)) {
|
||||||
*out++ = '.';
|
*out++ = '.';
|
||||||
write(ms.count(), 3);
|
write(ms.count(), 3);
|
||||||
|
@ -251,7 +251,7 @@ namespace uintptr {
|
|||||||
struct uintptr_t {
|
struct uintptr_t {
|
||||||
unsigned char value[sizeof(void*)];
|
unsigned char value[sizeof(void*)];
|
||||||
};
|
};
|
||||||
}
|
} // namespace uintptr
|
||||||
using uintptr::uintptr_t;
|
using uintptr::uintptr_t;
|
||||||
typedef std::numeric_limits<uintptr_t> numutil;
|
typedef std::numeric_limits<uintptr_t> numutil;
|
||||||
|
|
||||||
@ -1113,10 +1113,7 @@ FMT_CONSTEXPR unsigned basic_parse_context<Char, ErrorHandler>::next_arg_id() {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
namespace grisu_options {
|
namespace grisu_options {
|
||||||
enum {
|
enum { fixed = 1, grisu3 = 2 };
|
||||||
fixed = 1,
|
|
||||||
grisu3 = 2
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats value using the Grisu algorithm:
|
// 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) {
|
if (!params.trailing_zeros) {
|
||||||
// Remove trailing zeros.
|
// Remove trailing zeros.
|
||||||
while (size > full_exp && digits[size - 1] == '0') --size;
|
while (size > full_exp && digits[size - 1] == '0') --size;
|
||||||
if (size != full_exp)
|
if (size != full_exp) *it++ = static_cast<Char>('.');
|
||||||
*it++ = static_cast<Char>('.');
|
|
||||||
return copy_str<Char>(digits + full_exp, digits + size, it);
|
return copy_str<Char>(digits + full_exp, digits + size, it);
|
||||||
}
|
}
|
||||||
*it++ = static_cast<Char>('.');
|
*it++ = static_cast<Char>('.');
|
||||||
@ -2877,7 +2873,7 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
|
|||||||
(spec.type != 'a' && spec.type != 'A' && spec.type != 'e' &&
|
(spec.type != 'a' && spec.type != 'A' && spec.type != 'e' &&
|
||||||
spec.type != 'E') &&
|
spec.type != 'E') &&
|
||||||
internal::grisu_format(static_cast<double>(value), buffer,
|
internal::grisu_format(static_cast<double>(value), buffer,
|
||||||
precision, options, exp);
|
precision, options, exp);
|
||||||
if (!use_grisu) internal::sprintf_format(value, buffer, spec);
|
if (!use_grisu) internal::sprintf_format(value, buffer, spec);
|
||||||
|
|
||||||
if (handler.as_percentage) {
|
if (handler.as_percentage) {
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
#include "chrono.h"
|
#include "chrono.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#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
|
#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
|
||||||
|
|
||||||
#endif // FMT_TIME_H_
|
#endif // FMT_TIME_H_
|
||||||
|
@ -318,6 +318,10 @@ TEST(ChronoTest, SpecialDurations) {
|
|||||||
fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan)));
|
fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan)));
|
||||||
fmt::format("{:%S}",
|
fmt::format("{:%S}",
|
||||||
std::chrono::duration<float, std::atto>(1.79400457e+31f));
|
std::chrono::duration<float, std::atto>(1.79400457e+31f));
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::exa>(1)),
|
||||||
|
"1Es");
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)),
|
||||||
|
"1as");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
Reference in New Issue
Block a user