Skip to content

Commit 7d2a6ac

Browse files
committed
Fix timezone handling in tm
1 parent f10b6dd commit 7d2a6ac

File tree

2 files changed

+35
-14
lines changed

2 files changed

+35
-14
lines changed

include/fmt/chrono.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -420,14 +420,11 @@ auto write(OutputIt out, const std::tm& time, const std::locale& loc,
420420
return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc);
421421
}
422422

423-
template <typename Rep1, typename Rep2>
424-
struct is_same_arithmetic_type
425-
: public std::integral_constant<bool,
426-
(std::is_integral<Rep1>::value &&
427-
std::is_integral<Rep2>::value) ||
428-
(std::is_floating_point<Rep1>::value &&
429-
std::is_floating_point<Rep2>::value)> {
430-
};
423+
template <typename T, typename U>
424+
using is_similar_arithmetic_type =
425+
bool_constant<(std::is_integral<T>::value && std::is_integral<U>::value) ||
426+
(std::is_floating_point<T>::value &&
427+
std::is_floating_point<U>::value)>;
431428

432429
FMT_NORETURN inline void throw_duration_error() {
433430
FMT_THROW(format_error("cannot format duration"));
@@ -486,9 +483,9 @@ auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
486483
#endif
487484
}
488485

489-
template <
490-
typename To, typename FromRep, typename FromPeriod,
491-
FMT_ENABLE_IF(!is_same_arithmetic_type<FromRep, typename To::rep>::value)>
486+
template <typename To, typename FromRep, typename FromPeriod,
487+
FMT_ENABLE_IF(
488+
!is_similar_arithmetic_type<FromRep, typename To::rep>::value)>
492489
auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
493490
// Mixed integer <-> float cast is not supported by safe_duration_cast.
494491
return std::chrono::duration_cast<To>(from);
@@ -520,6 +517,7 @@ template <typename... T> auto current_zone(T...) -> time_zone* {
520517
template <typename... T> void _tzset(T...) {}
521518
} // namespace tz
522519

520+
// DEPRECATED!
523521
inline void tzset_once() {
524522
static bool init = []() {
525523
using namespace tz;
@@ -2227,8 +2225,10 @@ template <typename Char> struct formatter<std::tm, Char> {
22272225
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
22282226
}
22292227

2230-
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
2231-
bool no_timezone = false) -> const Char* {
2228+
FMT_CONSTEXPR auto do_parse(
2229+
parse_context<Char>& ctx,
2230+
bool no_timezone = !detail::has_member_data_tm_gmtoff<T>::value)
2231+
-> const Char* {
22322232
auto it = ctx.begin(), end = ctx.end();
22332233
if (it == end || *it == '}') return it;
22342234

test/chrono-test.cc

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
using fmt::runtime;
1818
using fmt::sys_time;
19-
using fmt::sys_time;
2019
using testing::Contains;
2120

2221
#if defined(__MINGW32__) && !defined(_UCRT)
@@ -336,9 +335,31 @@ TEST(chrono_test, local_time) {
336335
fmt::format_error, "no timezone");
337336
}
338337

338+
template <typename T,
339+
FMT_ENABLE_IF(fmt::detail::has_member_data_tm_gmtoff<T>::value)>
340+
bool set_gmtoff(T& time, long offset) {
341+
time.tm_gmtoff = offset;
342+
return true;
343+
}
344+
template <typename T,
345+
FMT_ENABLE_IF(!fmt::detail::has_member_data_tm_gmtoff<T>::value)>
346+
bool set_gmtoff(T&, long) {
347+
return false;
348+
}
349+
339350
TEST(chrono_test, tm) {
340351
auto time = fmt::gmtime(290088000);
341352
test_time(time);
353+
if (set_gmtoff(time, -28800)) {
354+
EXPECT_EQ(fmt::format(fmt::runtime("{:%z}"), time), "-0800");
355+
EXPECT_EQ(fmt::format(fmt::runtime("{:%Ez}"), time), "-08:00");
356+
EXPECT_EQ(fmt::format(fmt::runtime("{:%Oz}"), time), "-08:00");
357+
} else {
358+
EXPECT_THROW_MSG((void)fmt::format(fmt::runtime("{:%z}"), time),
359+
fmt::format_error, "no timezone");
360+
EXPECT_THROW_MSG((void)fmt::format(fmt::runtime("{:%Z}"), time),
361+
fmt::format_error, "no timezone");
362+
}
342363
}
343364

344365
TEST(chrono_test, daylight_savings_time_end) {

0 commit comments

Comments
 (0)