diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index b957ab6f..b48b0d98 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1046,26 +1046,6 @@ inline Int to_nonnegative_int(T value, Int upper) { return static_cast(value); } -template ::is_signed)> -constexpr std::chrono::duration abs( - std::chrono::duration d) { - // We need to compare the duration using the count() method directly - // due to a compiler bug in clang-11 regarding the spaceship operator, - // when -Wzero-as-null-pointer-constant is enabled. - // In clang-12 the bug has been fixed. See - // https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example: - // https://www.godbolt.org/z/Knbb5joYx. - return d.count() >= d.zero().count() ? d : -d; -} - -template ::is_signed)> -constexpr std::chrono::duration abs( - std::chrono::duration d) { - return d; -} - constexpr long long pow10(std::uint32_t n) { return n == 0 ? 1 : 10 * pow10(n - 1); } @@ -1101,7 +1081,7 @@ void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) { std::ratio<1, detail::pow10(num_fractional_digits)>>; const auto fractional = - detail::abs(d) - std::chrono::duration_cast(d); + d - std::chrono::duration_cast(d); const auto subseconds = std::chrono::treat_as_floating_point< typename subsecond_precision::rep>::value @@ -2125,9 +2105,14 @@ struct formatter, if (period::num != 1 || period::den != 1 || std::is_floating_point::value) { const auto epoch = val.time_since_epoch(); - const auto subsecs = std::chrono::duration_cast( + auto subsecs = std::chrono::duration_cast( epoch - std::chrono::duration_cast(epoch)); + if (subsecs.count() < 0) { + subsecs += std::chrono::seconds(1); + val -= std::chrono::seconds(1); + } + return formatter::do_format( gmtime(std::chrono::time_point_cast(val)), ctx, &subsecs); diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 65e99a9c..2d20013f 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -908,4 +908,14 @@ TEST(chrono_test, timestamps_sub_seconds) { t10(std::chrono::milliseconds(2000)); EXPECT_EQ(fmt::format("{:%S}", t10), "02.000"); + + { + const auto epoch = std::chrono::time_point(); + const auto d = std::chrono::milliseconds(250); + + EXPECT_EQ("59.750", fmt::format("{:%S}", epoch - d)); + EXPECT_EQ("00.000", fmt::format("{:%S}", epoch)); + EXPECT_EQ("00.250", fmt::format("{:%S}", epoch + d)); + } }