Skip to content

Commit d4187b9

Browse files
committed
Fix formatting of timezone names
1 parent bd9554a commit d4187b9

2 files changed

Lines changed: 38 additions & 37 deletions

File tree

include/fmt/chrono.h

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -991,16 +991,28 @@ inline auto tm_mon_short_name(int mon) -> const char* {
991991
}
992992

993993
template <typename T, typename = void>
994-
struct has_member_data_tm_gmtoff : std::false_type {};
994+
struct has_tm_gmtoff : std::false_type {};
995995
template <typename T>
996-
struct has_member_data_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>>
997-
: std::true_type {};
996+
struct has_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>> : std::true_type {};
998997

999-
template <typename T, typename = void>
1000-
struct has_member_data_tm_zone : std::false_type {};
998+
template <typename T, typename = void> struct has_tm_zone : std::false_type {};
1001999
template <typename T>
1002-
struct has_member_data_tm_zone<T, void_t<decltype(T::tm_zone)>>
1003-
: std::true_type {};
1000+
struct has_tm_zone<T, void_t<decltype(T::tm_zone)>> : std::true_type {};
1001+
1002+
template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
1003+
bool set_tm_zone(T& time, char* tz) {
1004+
time.tm_zone = tz;
1005+
return true;
1006+
}
1007+
template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
1008+
bool set_tm_zone(T&, char*) {
1009+
return false;
1010+
}
1011+
1012+
inline char* utc() {
1013+
static char tz[] = "UTC";
1014+
return tz;
1015+
}
10041016

10051017
// Converts value to Int and checks that it's in the range [0, upper).
10061018
template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
@@ -1260,24 +1272,24 @@ class tm_writer {
12601272
write2(static_cast<int>(offset % 60));
12611273
}
12621274

1263-
template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
1264-
void format_utc_offset_impl(const T& tm, numeric_system ns) {
1275+
template <typename T, FMT_ENABLE_IF(has_tm_gmtoff<T>::value)>
1276+
void format_utc_offset(const T& tm, numeric_system ns) {
12651277
write_utc_offset(tm.tm_gmtoff, ns);
12661278
}
1267-
template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
1268-
void format_utc_offset_impl(const T&, numeric_system ns) {
1279+
template <typename T, FMT_ENABLE_IF(!has_tm_gmtoff<T>::value)>
1280+
void format_utc_offset(const T&, numeric_system ns) {
12691281
write_utc_offset(0, ns);
12701282
}
12711283

1272-
template <typename T, FMT_ENABLE_IF(has_member_data_tm_zone<T>::value)>
1273-
void format_tz_name_impl(const T& tm) {
1284+
template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
1285+
void format_tz_name(const T& tm) {
12741286
if (is_classic_)
12751287
out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
12761288
else
12771289
format_localized('Z');
12781290
}
1279-
template <typename T, FMT_ENABLE_IF(!has_member_data_tm_zone<T>::value)>
1280-
void format_tz_name_impl(const T&) {
1291+
template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
1292+
void format_tz_name(const T&) {
12811293
format_localized('Z');
12821294
}
12831295

@@ -1389,8 +1401,8 @@ class tm_writer {
13891401
out_ = copy<Char>(std::begin(buf) + offset, std::end(buf), out_);
13901402
}
13911403

1392-
void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); }
1393-
void on_tz_name() { format_tz_name_impl(tm_); }
1404+
void on_utc_offset(numeric_system ns) { format_utc_offset(tm_, ns); }
1405+
void on_tz_name() { format_tz_name(tm_); }
13941406

13951407
void on_year(numeric_system ns, pad_type pad) {
13961408
if (is_classic_ || ns == numeric_system::standard)
@@ -2236,7 +2248,7 @@ template <typename Char> struct formatter<std::tm, Char> {
22362248

22372249
public:
22382250
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2239-
return do_parse(ctx, detail::has_member_data_tm_gmtoff<std::tm>::value);
2251+
return do_parse(ctx, detail::has_tm_gmtoff<std::tm>::value);
22402252
}
22412253

22422254
template <typename FormatContext>
@@ -2261,17 +2273,20 @@ struct formatter<sys_time<Duration>, Char> : private formatter<std::tm, Char> {
22612273
if (detail::const_check(
22622274
period::num == 1 && period::den == 1 &&
22632275
!std::is_floating_point<typename Duration::rep>::value)) {
2276+
detail::set_tm_zone(tm, detail::utc());
22642277
return formatter<std::tm, Char>::format(tm, ctx);
22652278
}
22662279
Duration epoch = val.time_since_epoch();
22672280
Duration subsecs = detail::duration_cast<Duration>(
22682281
epoch - detail::duration_cast<std::chrono::seconds>(epoch));
22692282
if (subsecs.count() < 0) {
22702283
auto second = detail::duration_cast<Duration>(std::chrono::seconds(1));
2271-
if (tm.tm_sec != 0)
2284+
if (tm.tm_sec != 0) {
22722285
--tm.tm_sec;
2273-
else
2286+
} else {
22742287
tm = gmtime(val - second);
2288+
detail::set_tm_zone(tm, detail::utc());
2289+
}
22752290
subsecs += second;
22762291
}
22772292
return formatter<std::tm, Char>::do_format(tm, ctx, &subsecs);

test/chrono-test.cc

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -335,30 +335,16 @@ TEST(chrono_test, local_time) {
335335
fmt::format_error, "no timezone");
336336
}
337337

338-
template <typename T,
339-
FMT_ENABLE_IF(fmt::detail::has_member_data_tm_gmtoff<T>::value)>
338+
template <typename T, FMT_ENABLE_IF(fmt::detail::has_tm_gmtoff<T>::value)>
340339
bool set_tm_gmtoff(T& time, long offset) {
341340
time.tm_gmtoff = offset;
342341
return true;
343342
}
344-
template <typename T,
345-
FMT_ENABLE_IF(!fmt::detail::has_member_data_tm_gmtoff<T>::value)>
343+
template <typename T, FMT_ENABLE_IF(!fmt::detail::has_tm_gmtoff<T>::value)>
346344
bool set_tm_gmtoff(T&, long) {
347345
return false;
348346
}
349347

350-
template <typename T,
351-
FMT_ENABLE_IF(fmt::detail::has_member_data_tm_zone<T>::value)>
352-
bool set_tm_zone(T& time, char* tz) {
353-
time.tm_zone = tz;
354-
return true;
355-
}
356-
template <typename T,
357-
FMT_ENABLE_IF(!fmt::detail::has_member_data_tm_zone<T>::value)>
358-
bool set_tm_zone(T&, char*) {
359-
return false;
360-
}
361-
362348
TEST(chrono_test, tm) {
363349
auto time = fmt::gmtime(290088000);
364350
test_time(time);
@@ -371,7 +357,7 @@ TEST(chrono_test, tm) {
371357
fmt::format_error, "no timezone");
372358
}
373359
char tz[] = "EET";
374-
if (set_tm_zone(time, tz)) {
360+
if (fmt::detail::set_tm_zone(time, tz)) {
375361
EXPECT_EQ(fmt::format(fmt::runtime("{:%Z}"), time), "EET");
376362
} else {
377363
EXPECT_THROW_MSG((void)fmt::format(fmt::runtime("{:%Z}"), time),

0 commit comments

Comments
 (0)