Test ambiguous time

This commit is contained in:
Victor Zverovich
2025-03-23 09:49:23 -07:00
parent 989826ce50
commit 43e31614cc
3 changed files with 24 additions and 9 deletions

View File

@ -58,7 +58,7 @@ jobs:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- name: Set timezone
run: sudo timedatectl set-timezone 'Europe/Minsk'
run: sudo timedatectl set-timezone 'Europe/Kyiv'
- name: Install GCC 4.9
run: |

View File

@ -2320,15 +2320,20 @@ struct formatter<local_time<Duration>, Char> : formatter<std::tm, Char> {
template <typename FormatContext>
auto format(local_time<Duration> val, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto time_since_epoch = val.time_since_epoch();
auto seconds_since_epoch =
detail::duration_cast<std::chrono::seconds>(time_since_epoch);
// Use gmtime to prevent time conversion since local_time has an
// unspecified time zone.
auto t = gmtime(seconds_since_epoch.count());
using period = typename Duration::period;
if (period::num == 1 && period::den == 1 &&
!std::is_floating_point<typename Duration::rep>::value) {
return formatter<std::tm, Char>::format(localtime(val), ctx);
return formatter<std::tm, Char>::format(t, ctx);
}
auto epoch = val.time_since_epoch();
auto subsecs = detail::duration_cast<Duration>(
epoch - detail::duration_cast<std::chrono::seconds>(epoch));
return formatter<std::tm, Char>::do_format(localtime(val), ctx, &subsecs);
auto subsecs =
detail::duration_cast<Duration>(time_since_epoch - seconds_since_epoch);
return formatter<std::tm, Char>::do_format(t, ctx, &subsecs);
}
};

View File

@ -428,6 +428,18 @@ TEST(chrono_test, local_system_clock_time_point) {
#endif // FMT_USE_LOCAL_TIME
TEST(chrono_test, daylight_savings_time_end) {
// 2024-10-27 03:05 as the number of seconds since epoch in Europe/Kyiv time.
// It is slightly after the DST end and passing it to to_sys will result in
// an ambiguous time error:
// 2024-10-27 03:05:00 is ambiguous. It could be
// 2024-10-27 03:05:00 EEST == 2024-10-27 00:05:00 UTC or
// 2024-10-27 03:05:00 EET == 2024-10-27 01:05:00 UTC
auto t =
fmt::local_time<std::chrono::seconds>(std::chrono::seconds(1729998300));
EXPECT_EQ(fmt::format("{}", t), "2024-10-27 03:05:00");
}
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
TEST(chrono_test, format_default) {
@ -1033,7 +1045,7 @@ TEST(chrono_test, glibc_extensions) {
{
auto t = std::tm();
t.tm_year = -5 - 1900;
EXPECT_EQ(fmt::format( "{:%Y}", t), "-005");
EXPECT_EQ(fmt::format("{:%Y}", t), "-005");
EXPECT_EQ(fmt::format("{:%_Y}", t), " -5");
EXPECT_EQ(fmt::format("{:%-Y}", t), "-5");
}
@ -1045,8 +1057,6 @@ TEST(chrono_test, glibc_extensions) {
EXPECT_EQ(fmt::format("{:%_m}", t), " 7");
EXPECT_EQ(fmt::format("{:%-m}", t), "7");
}
}
TEST(chrono_test, out_of_range) {