Merge 40ed39dc3b22bf38eaefa2288230aa600f1927ef into 2eda43e9be177109a1557a59eee3fe7825a9b479

This commit is contained in:
ViktarL 2026-02-04 00:52:38 +00:00 committed by GitHub
commit 8b32b64a6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 70 additions and 0 deletions

View File

@ -264,6 +264,15 @@ using utc_time = std::chrono::time_point<detail::utc_clock, Duration>;
template <class Duration>
using local_time = std::chrono::time_point<detail::local_t, Duration>;
// 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.
@ -2238,6 +2247,40 @@ struct formatter<local_time<Duration>, Char>
}
};
#if FMT_HAVE_STD_ZONED_TIME
template <typename Duration, typename TimeZonePtr, typename Char>
struct formatter<std::chrono::zoned_time<Duration, TimeZonePtr>, Char,
std::enable_if_t<std::is_pointer_v<TimeZonePtr>>>
: private formatter<std::tm, Char> {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return this->do_parse(ctx, true);
}
template <typename FormatContext>
auto format(const std::chrono::zoned_time<Duration, TimeZonePtr>& 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<std::chrono::seconds>(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<std::tm>::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<typename Duration::rep>::value) {
return formatter<std::tm, Char>::format(t, ctx);
}
auto subsecs =
detail::duration_cast<Duration>(time_since_epoch - seconds_since_epoch);
return formatter<std::tm, Char>::do_format(t, ctx, &subsecs);
}
};
#endif
FMT_END_EXPORT
FMT_END_NAMESPACE

View File

@ -1021,3 +1021,30 @@ TEST(chrono_test, year_month_day) {
EXPECT_THAT(months, Contains(fmt::format(loc, "{:L%b}", month)));
}
}
#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907L
TEST(chrono_test, zoned_time) {
const static std::map<std::string, std::pair<std::string, std::string>> map_to_test{
{"Africa/Cairo", {"EET", "+0200"}},
{"Africa/Johannesburg", {"SAST", "+0200"}},
{"America/Chicago", {"CST", "-0600"}},
{"America/Denver", {"MST", "-0700"}},
{"America/Los_Angeles", {"PST", "-0800"}},
{"America/New_York", {"EST", "-0500"}},
{"Asia/Kolkata", {"IST", "+0530"}},
{"Asia/Riyadh", {"+03", "+0300"}},
{"Asia/Shanghai", {"CST", "+0800"}},
{"Asia/Tokyo", {"JST", "+0900"}},
{"Australia/Sydney", {"AEDT", "+1100"}},
{"Europe/Berlin", {"CET", "+0100"}},
{"Europe/London", {"GMT", "+0000"}},
{"Europe/Paris", {"CET", "+0100"}},
{"Pacific/Auckland", {"NZDT", "+1300"}}};
for (const auto& entry : map_to_test) {
const std::chrono::zoned_time entry_to_test{std::chrono::locate_zone(entry.first),
std::chrono::system_clock::now()};
EXPECT_EQ(fmt::format("{:%Z}", entry_to_test), entry.second.first);
EXPECT_EQ(fmt::format("{:%z}", entry_to_test), entry.second.second);
}
}
#endif