Skip to content

Commit 40ed39d

Browse files
committed
zoned_time
1 parent 0e078f6 commit 40ed39d

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

include/fmt/chrono.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,15 @@ using utc_time = std::chrono::time_point<detail::utc_clock, Duration>;
265265
template <class Duration>
266266
using local_time = std::chrono::time_point<detail::local_t, Duration>;
267267

268+
// Check if std::chrono::zoned_time is available.
269+
#ifdef FMT_HAVE_STD_ZONED_TIME
270+
// Use the provided definition.
271+
#elif defined(__cpp_lib_chrono)
272+
# define FMT_HAVE_STD_ZONED_TIME (__cpp_lib_chrono >= 201907L)
273+
#else
274+
# define FMT_HAVE_STD_ZONED_TIME 0
275+
#endif
276+
268277
namespace detail {
269278

270279
// Prevents expansion of a preceding token as a function-style macro.
@@ -2240,6 +2249,40 @@ struct formatter<local_time<Duration>, Char>
22402249
}
22412250
};
22422251

2252+
#if FMT_HAVE_STD_ZONED_TIME
2253+
template <typename Duration, typename TimeZonePtr, typename Char>
2254+
struct formatter<std::chrono::zoned_time<Duration, TimeZonePtr>, Char,
2255+
std::enable_if_t<std::is_pointer_v<TimeZonePtr>>>
2256+
: private formatter<std::tm, Char> {
2257+
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2258+
return this->do_parse(ctx, true);
2259+
}
2260+
2261+
template <typename FormatContext>
2262+
auto format(const std::chrono::zoned_time<Duration, TimeZonePtr>& val,
2263+
FormatContext& ctx) const -> decltype(ctx.out()) {
2264+
auto time_info = val.get_info();
2265+
auto time_since_epoch = val.get_local_time().time_since_epoch();
2266+
auto seconds_since_epoch =
2267+
detail::duration_cast<std::chrono::seconds>(time_since_epoch);
2268+
std::tm t = gmtime(seconds_since_epoch.count());
2269+
// Create a custom tm with timezone info if supported
2270+
if constexpr (detail::has_tm_zone<std::tm>::value) {
2271+
t.tm_zone = time_info.abbrev.c_str();
2272+
t.tm_gmtoff = time_info.offset.count();
2273+
}
2274+
using period = typename Duration::period;
2275+
if (period::num == 1 && period::den == 1 &&
2276+
!std::is_floating_point<typename Duration::rep>::value) {
2277+
return formatter<std::tm, Char>::format(t, ctx);
2278+
}
2279+
auto subsecs =
2280+
detail::duration_cast<Duration>(time_since_epoch - seconds_since_epoch);
2281+
return formatter<std::tm, Char>::do_format(t, ctx, &subsecs);
2282+
}
2283+
};
2284+
#endif
2285+
22432286
FMT_END_EXPORT
22442287
FMT_END_NAMESPACE
22452288

test/chrono-test.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,3 +1021,30 @@ TEST(chrono_test, year_month_day) {
10211021
EXPECT_THAT(months, Contains(fmt::format(loc, "{:L%b}", month)));
10221022
}
10231023
}
1024+
1025+
#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907L
1026+
TEST(chrono_test, zoned_time) {
1027+
const static std::map<std::string, std::pair<std::string, std::string>> map_to_test{
1028+
{"Africa/Cairo", {"EET", "+0200"}},
1029+
{"Africa/Johannesburg", {"SAST", "+0200"}},
1030+
{"America/Chicago", {"CST", "-0600"}},
1031+
{"America/Denver", {"MST", "-0700"}},
1032+
{"America/Los_Angeles", {"PST", "-0800"}},
1033+
{"America/New_York", {"EST", "-0500"}},
1034+
{"Asia/Kolkata", {"IST", "+0530"}},
1035+
{"Asia/Riyadh", {"+03", "+0300"}},
1036+
{"Asia/Shanghai", {"CST", "+0800"}},
1037+
{"Asia/Tokyo", {"JST", "+0900"}},
1038+
{"Australia/Sydney", {"AEDT", "+1100"}},
1039+
{"Europe/Berlin", {"CET", "+0100"}},
1040+
{"Europe/London", {"GMT", "+0000"}},
1041+
{"Europe/Paris", {"CET", "+0100"}},
1042+
{"Pacific/Auckland", {"NZDT", "+1300"}}};
1043+
for (const auto& entry : map_to_test) {
1044+
const std::chrono::zoned_time entry_to_test{std::chrono::locate_zone(entry.first),
1045+
std::chrono::system_clock::now()};
1046+
EXPECT_EQ(fmt::format("{:%Z}", entry_to_test), entry.second.first);
1047+
EXPECT_EQ(fmt::format("{:%z}", entry_to_test), entry.second.second);
1048+
}
1049+
}
1050+
#endif

0 commit comments

Comments
 (0)