@@ -265,6 +265,20 @@ using utc_time = std::chrono::time_point<detail::utc_clock, Duration>;
265265template <class Duration >
266266using 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_TEST
270+ // Use the provided definition.
271+ #elif defined(__cpp_lib_chrono)
272+ # define FMT_HAVE_STD_ZONED_TIME_TEST (__cpp_lib_chrono >= 201907L )
273+ #else
274+ # define FMT_HAVE_STD_ZONED_TIME_TEST 0
275+ #endif
276+
277+ #if FMT_HAVE_STD_ZONED_TIME_TEST
278+ template <typename Duration, typename TimeZonePtr>
279+ using zoned_time = std::chrono::zoned_time<Duration, TimeZonePtr>;
280+ #endif
281+
268282namespace detail {
269283
270284// Prevents expansion of a preceding token as a function-style macro.
@@ -2240,6 +2254,42 @@ struct formatter<local_time<Duration>, Char>
22402254 }
22412255};
22422256
2257+ #if FMT_HAVE_STD_ZONED_TIME_TEST
2258+ template <typename Duration, typename TimeZonePtr, typename Char>
2259+ struct formatter <zoned_time<Duration, TimeZonePtr>, Char,
2260+ std::enable_if_t <std::is_pointer_v<TimeZonePtr>>>
2261+ : private formatter<std::tm, Char> {
2262+ FMT_CONSTEXPR auto parse (parse_context<Char>& ctx) -> const Char* {
2263+ return this ->do_parse (ctx, true );
2264+ }
2265+
2266+ template <typename FormatContext>
2267+ auto format (const std::chrono::zoned_time<Duration, TimeZonePtr>& val,
2268+ FormatContext& ctx) const -> decltype(ctx.out()) {
2269+ auto time_info = val.get_info ();
2270+ auto time_since_epoch = val.get_local_time ().time_since_epoch ();
2271+ auto seconds_since_epoch =
2272+ detail::duration_cast<std::chrono::seconds>(time_since_epoch);
2273+ // Use gmtime to prevent time zone conversion since local_time has an
2274+ // unspecified time zone.
2275+ std::tm t = gmtime (seconds_since_epoch.count ());
2276+ // Create a custom tm with timezone info if supported
2277+ if constexpr (detail::has_tm_zone<std::tm>::value) {
2278+ t.tm_zone = time_info.abbrev .c_str ();
2279+ t.tm_gmtoff = time_info.offset .count ();
2280+ }
2281+ using period = typename Duration::period;
2282+ if (period::num == 1 && period::den == 1 &&
2283+ !std::is_floating_point<typename Duration::rep>::value) {
2284+ return formatter<std::tm, Char>::format (t, ctx);
2285+ }
2286+ auto subsecs =
2287+ detail::duration_cast<Duration>(time_since_epoch - seconds_since_epoch);
2288+ return formatter<std::tm, Char>::do_format (t, ctx, &subsecs);
2289+ }
2290+ };
2291+ #endif
2292+
22432293FMT_END_EXPORT
22442294FMT_END_NAMESPACE
22452295
0 commit comments