From da776c9a66ed6d4b105e067fcdfabf77f42ac671 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 6 Apr 2025 10:18:11 -0700 Subject: [PATCH] Test timezone --- include/fmt/chrono.h | 24 +--------- test/chrono-test.cc | 8 +++- test/xchar-test.cc | 101 +------------------------------------------ 3 files changed, 10 insertions(+), 123 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 8024ddf5..252bfd3d 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1268,28 +1268,8 @@ class tm_writer { write_utc_offset(tm.tm_gmtoff, ns); } template ::value)> - void format_utc_offset_impl(const T& tm, numeric_system ns) { -#if defined(_WIN32) && defined(_UCRT) - tzset_once(); - long offset = 0; - _get_timezone(&offset); - if (tm.tm_isdst) { - long dstbias = 0; - _get_dstbias(&dstbias); - offset += dstbias; - } - write_utc_offset(-offset, ns); -#else - if (ns == numeric_system::standard) return format_localized('z'); - - // Extract timezone offset from timezone conversion functions. - std::tm gtm = tm; - std::time_t gt = std::mktime(>m); - std::tm ltm = gmtime(gt); - std::time_t lt = std::mktime(<m); - long long offset = gt - lt; - write_utc_offset(offset, ns); -#endif + void format_utc_offset_impl(const T&, numeric_system ns) { + write_utc_offset(0, ns); } template ::value)> diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 7466301e..d8b9f055 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -263,7 +263,11 @@ auto strftime_full_utc(TimePoint tp) -> std::string { return system_strftime("%Y-%m-%d %H:%M:%S", &tm); } -TEST(chrono_test, system_clock_time_point) { +TEST(chrono_test, sys_time) { + auto time = + fmt::sys_time(std::chrono::seconds(290088000)); + EXPECT_EQ(fmt::format("{:%z}", time), "+0000"); + auto t1 = std::chrono::time_point_cast( std::chrono::system_clock::now()); EXPECT_EQ(strftime_full_utc(t1), fmt::format("{:%Y-%m-%d %H:%M:%S}", t1)); @@ -303,7 +307,7 @@ TEST(chrono_test, system_clock_time_point) { } // Timezone formatters tests makes sense for localtime. -#if FMT_HAS_C99_STRFTIME +#if FMT_HAS_C99_STRFTIME && !defined(_WIN32) spec_list = {"%z", "%Z"}; #else spec_list = {"%Z"}; diff --git a/test/xchar-test.cc b/test/xchar-test.cc index fd613e82..44b19e87 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -224,106 +224,9 @@ TEST(xchar_test, chrono) { EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42))); EXPECT_EQ(fmt::format(L"{:%F}", tm), L"2016-04-25"); EXPECT_EQ(fmt::format(L"{:%T}", tm), L"11:22:33"); -} -std::wstring system_wcsftime(const std::wstring& format, const std::tm* timeptr, - std::locale* locptr = nullptr) { - auto loc = locptr ? *locptr : std::locale::classic(); - auto& facet = std::use_facet>(loc); - std::wostringstream os; - os.imbue(loc); - facet.put(os, os, L' ', timeptr, format.c_str(), - format.c_str() + format.size()); -#ifdef _WIN32 - // Workaround a bug in older versions of Universal CRT. - auto str = os.str(); - if (str == L"-0000") str = L"+0000"; - return str; -#else - return os.str(); -#endif -} - -TEST(chrono_test_wchar, time_point) { - auto t1 = std::chrono::time_point_cast( - std::chrono::system_clock::now()); - - std::vector spec_list = { - L"%%", L"%n", L"%t", L"%Y", L"%EY", L"%y", L"%Oy", L"%Ey", L"%C", - L"%EC", L"%G", L"%g", L"%b", L"%h", L"%B", L"%m", L"%Om", L"%U", - L"%OU", L"%W", L"%OW", L"%V", L"%OV", L"%j", L"%d", L"%Od", L"%e", - L"%Oe", L"%a", L"%A", L"%w", L"%Ow", L"%u", L"%Ou", L"%H", L"%OH", - L"%I", L"%OI", L"%M", L"%OM", L"%S", L"%OS", L"%x", L"%Ex", L"%X", - L"%EX", L"%D", L"%F", L"%R", L"%T", L"%p"}; -#ifndef _WIN32 - // Disabled on Windows, because these formats is not consistent among - // platforms. - spec_list.insert(spec_list.end(), {L"%c", L"%Ec", L"%r"}); -#elif !FMT_HAS_C99_STRFTIME - // Only C89 conversion specifiers when using MSVCRT instead of UCRT - spec_list = {L"%%", L"%Y", L"%y", L"%b", L"%B", L"%m", L"%U", - L"%W", L"%j", L"%d", L"%a", L"%A", L"%w", L"%H", - L"%I", L"%M", L"%S", L"%x", L"%X", L"%p"}; -#endif - spec_list.push_back(L"%Y-%m-%d %H:%M:%S"); - - for (const auto& spec : spec_list) { - auto t = std::chrono::system_clock::to_time_t(t1); - auto tm = *std::gmtime(&t); - - auto sys_output = system_wcsftime(spec, &tm); - - auto fmt_spec = fmt::format(L"{{:{}}}", spec); - EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), t1)); - EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), tm)); - } - - // Timezone formatters tests makes sense for localtime. -#if FMT_HAS_C99_STRFTIME - spec_list = {L"%z", L"%Z"}; -#else - spec_list = {L"%Z"}; -#endif - for (const auto& spec : spec_list) { - auto t = std::chrono::system_clock::to_time_t(t1); - auto tm = *std::localtime(&t); - - auto sys_output = system_wcsftime(spec, &tm); - - auto fmt_spec = fmt::format(L"{{:{}}}", spec); - EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), tm)); - - if (spec == L"%z") { - sys_output.insert(sys_output.end() - 2, 1, L':'); - EXPECT_EQ(sys_output, fmt::format(L"{:%Ez}", tm)); - EXPECT_EQ(sys_output, fmt::format(L"{:%Oz}", tm)); - } - } - - // Separate tests for UTC, since std::time_put can use local time and ignoring - // the timezone in std::tm (if it presents on platform). - if (fmt::detail::has_member_data_tm_zone::value) { - auto t = std::chrono::system_clock::to_time_t(t1); - auto tm = *std::gmtime(&t); - - std::vector tz_names = {L"GMT", L"UTC"}; - EXPECT_THAT(tz_names, Contains(fmt::format(L"{:%Z}", t1))); - EXPECT_THAT(tz_names, Contains(fmt::format(L"{:%Z}", tm))); - } - - if (fmt::detail::has_member_data_tm_gmtoff::value) { - auto t = std::chrono::system_clock::to_time_t(t1); - auto tm = *std::gmtime(&t); - - EXPECT_EQ(L"+0000", fmt::format(L"{:%z}", t1)); - EXPECT_EQ(L"+0000", fmt::format(L"{:%z}", tm)); - - EXPECT_EQ(L"+00:00", fmt::format(L"{:%Ez}", t1)); - EXPECT_EQ(L"+00:00", fmt::format(L"{:%Ez}", tm)); - - EXPECT_EQ(L"+00:00", fmt::format(L"{:%Oz}", t1)); - EXPECT_EQ(L"+00:00", fmt::format(L"{:%Oz}", tm)); - } + auto t = fmt::sys_time(std::chrono::seconds(290088000)); + EXPECT_EQ(fmt::format("{:%Y-%m-%d %H:%M:%S}", t), "1979-03-12 12:00:00"); } TEST(xchar_test, color) {