diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 9fbeeed6798e..d092b5b87d27 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -265,6 +265,15 @@ using utc_time = std::chrono::time_point; template using local_time = std::chrono::time_point; +// Check if std::chrono::zoned_time is available. +#ifdef FMT_HAVE_STD_ZONED_TIME +// Use the provided definition. +#elif defined(__cpp_lib_chrono) +# define FMT_HAVE_STD_ZONED_TIME (__cpp_lib_chrono >= 201907L) +#else +# define FMT_HAVE_STD_ZONED_TIME 0 +#endif + namespace detail { // Prevents expansion of a preceding token as a function-style macro. @@ -2240,6 +2249,40 @@ struct formatter, Char> } }; +#if FMT_HAVE_STD_ZONED_TIME +template +struct formatter, Char, + std::enable_if_t>> + : private formatter { + FMT_CONSTEXPR auto parse(parse_context& ctx) -> const Char* { + return this->do_parse(ctx, true); + } + + template + auto format(const std::chrono::zoned_time& val, + FormatContext& ctx) const -> decltype(ctx.out()) { + auto time_info = val.get_info(); + auto time_since_epoch = val.get_local_time().time_since_epoch(); + auto seconds_since_epoch = + detail::duration_cast(time_since_epoch); + std::tm t = gmtime(seconds_since_epoch.count()); + // Create a custom tm with timezone info if supported + if constexpr (detail::has_tm_zone::value) { + t.tm_zone = time_info.abbrev.c_str(); + t.tm_gmtoff = time_info.offset.count(); + } + using period = typename Duration::period; + if (period::num == 1 && period::den == 1 && + !std::is_floating_point::value) { + return formatter::format(t, ctx); + } + auto subsecs = + detail::duration_cast(time_since_epoch - seconds_since_epoch); + return formatter::do_format(t, ctx, &subsecs); + } +}; +#endif + FMT_END_EXPORT FMT_END_NAMESPACE