diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index bda7cb73..10aa7e55 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -430,41 +430,47 @@ auto write(OutputIt out, const std::tm& time, const std::locale& loc, return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); } -#if FMT_SAFE_DURATION_CAST -// throwing version of safe_duration_cast -// only available for integer<->integer or float<->float casts -template ::value && - std::is_integral::value) || - (std::is_floating_point::value && - std::is_floating_point::value))> +template +struct is_same_arithmetic_type + : public std::integral_constant::value && + std::is_integral::value) || + (std::is_floating_point::value && + std::is_floating_point::value)> { +}; + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(is_same_arithmetic_type::value)> To fmt_duration_cast(std::chrono::duration from) { +#if FMT_SAFE_DURATION_CAST + // throwing version of safe_duration_cast + // only available for integer<->integer or float<->float casts int ec; To to = safe_duration_cast::safe_duration_cast(from, ec); if (ec) FMT_THROW(format_error("cannot format duration")); return to; -} -// mixed integer<->float cast is not supported with safe_duration_cast -// fallback to standard duration cast in this case -template ::value != - std::is_integral::value) && - (std::is_floating_point::value != - std::is_floating_point::value))> -To fmt_duration_cast(std::chrono::duration from) { - return std::chrono::duration_cast(from); -} #else -// standard duration cast, may overflow and invoke undefined behavior -template + // standard duration cast, may overflow and invoke undefined behavior + return std::chrono::duration_cast(from); +#endif +} + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(!is_same_arithmetic_type::value)> To fmt_duration_cast(std::chrono::duration from) { + // mixed integer<->float cast is not supported with safe_duration_cast + // fallback to standard duration cast in this case return std::chrono::duration_cast(from); } -#endif template std::time_t to_time_t( std::chrono::time_point time_point) { + // cannot use std::chrono::system_clock::to_time_t() since this would first + // require a cast to std::chrono::system_clock::time_point, which could + // overflow. return fmt_duration_cast>( time_point.time_since_epoch()) .count();