diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index ba4e6ad72550e..c3fee8a7fa3c5 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "format.h" @@ -871,6 +872,12 @@ inline const char* tm_mon_short_name(int mon) { return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; } +template +struct has_member_data_tm_gmtoff : std::false_type {}; +template +struct has_member_data_tm_gmtoff> + : std::true_type {}; + template class tm_writer { private: static constexpr int days_per_week = 7; @@ -988,6 +995,36 @@ template class tm_writer { } } + void write_utc_offset(long offset) { + if (offset < 0) { + *out_++ = '-'; + offset = -offset; + } else { + *out_++ = '+'; + } + offset /= 60; + write2(static_cast(offset / 60)); + write2(static_cast(offset % 60)); + } + void format_utc_offset_impl(std::true_type) { + write_utc_offset(tm_.tm_gmtoff); + } + void format_utc_offset_impl(std::false_type) { +#if defined(_WIN32) + _tzset(); + long offset = 0; + _get_timezone(&offset); + if (tm_.tm_isdst) { + long dstbias = 0; + _get_dstbias(&dstbias); + offset += dstbias; + } + write_utc_offset(-offset); +#else + format_localized('z'); +#endif + } + void format_localized(char format, char modifier = 0) { out_ = write(out_, tm_, loc_, format, modifier); } @@ -1094,7 +1131,9 @@ template class tm_writer { out_ = copy_str(std::begin(buf) + offset, std::end(buf), out_); } - void on_utc_offset() { format_localized('z'); } + void on_utc_offset() { + format_utc_offset_impl(has_member_data_tm_gmtoff{}); + } void on_tz_name() { format_localized('Z'); } void on_year(numeric_system ns) { diff --git a/test/chrono-test.cc b/test/chrono-test.cc index fc773c531c752..d72838560992b 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -49,7 +49,14 @@ std::string system_strftime(const std::string& format, const std::tm* timeptr, os.imbue(loc); facet.put(os, os, ' ', timeptr, format.c_str(), format.c_str() + format.size()); +#ifdef _WIN32 + // Workaround to early ucrt bug + auto str = os.str(); + if (str == "-0000") str = "+0000"; + return str; +#else return os.str(); +#endif } FMT_CONSTEXPR std::tm make_tm(int year, int mon, int mday, int hour, int min, diff --git a/test/xchar-test.cc b/test/xchar-test.cc index 8f98c05048828..adba08e9cbb53 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -277,7 +277,14 @@ std::wstring system_wcsftime(const std::wstring& format, const std::tm* timeptr, os.imbue(loc); facet.put(os, os, L' ', timeptr, format.c_str(), format.c_str() + format.size()); +#ifdef _WIN32 + // Workaround to early ucrt bug + auto str = os.str(); + if (str == L"-0000") str = L"+0000"; + return str; +#else return os.str(); +#endif } TEST(chrono_test, time_point) {