diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 898dcd14..d6f3742e 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1141,7 +1141,7 @@ template <> struct formatter { if (end.failed()) FMT_THROW(format_error("failed to format time")); auto s = os.str(); if (detail::is_utf8() && localized) { - // char16_t codecvt is broken in MSVC. + // char16_t and char32_t codecvts are broken in MSVC (linkage errors). using code_unit = conditional_t; auto& f = std::use_facet>(loc); diff --git a/test/unicode-test.cc b/test/unicode-test.cc index 821b1344..73cac58c 100644 --- a/test/unicode-test.cc +++ b/test/unicode-test.cc @@ -5,6 +5,8 @@ // // For the license information refer to format.h. +#include +#include #include #include "fmt/chrono.h" @@ -16,14 +18,31 @@ using testing::Contains; TEST(unicode_test, is_utf8) { EXPECT_TRUE(fmt::detail::is_utf8()); } TEST(unicode_test, legacy_locale) { - auto loc = get_locale("ru_RU.CP1251"); + auto loc = get_locale("ru_RU.CP1251", "Russian.1251"); if (loc == std::locale::classic()) return; + + auto s = std::string(); try { - EXPECT_THAT( - (std::vector{"День недели: пн", "День недели: Пн"}), - Contains(fmt::format(loc, "День недели: {:L}", fmt::weekday(1)))); + s = fmt::format(loc, "День недели: {:L}", fmt::weekday(1)); } catch (const fmt::format_error& e) { - // Formatting can fail due to unsupported encoding. + // Formatting can fail due to an unsupported encoding. fmt::print("Format error: {}\n", e.what()); + return; } + +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 500 + auto&& os = std::ostringstream(); + os.imbue(loc); + auto tm = std::tm(); + tm.tm_wday = 1; + os << std::put_time(&tm, "%a"); + auto wd = os.str(); + if (wd == "??") { + EXPECT_EQ(s, "День недели: ??"); + fmt::print("std::locale gives ?? as a weekday.\n"); + return; + } +#endif + EXPECT_THAT((std::vector{"День недели: пн", "День недели: Пн"}), + Contains(s)); } diff --git a/test/util.cc b/test/util.cc index 06eb0407..f4cb74ca 100644 --- a/test/util.cc +++ b/test/util.cc @@ -27,11 +27,20 @@ fmt::buffered_file open_buffered_file(FILE** fp) { return f; } -std::locale get_locale(const char* name) { +std::locale do_get_locale(const char* name) { try { return std::locale(name); } catch (const std::runtime_error&) { - fmt::print(stderr, "{} locale is missing.\n", name); } return std::locale::classic(); } + +std::locale get_locale(const char* name, const char* alt_name) { + auto loc = do_get_locale(name); + if (loc == std::locale::classic() && alt_name) { + loc = do_get_locale(alt_name); + } + if (loc == std::locale::classic()) + fmt::print(stderr, "{} locale is missing.\n", name); + return loc; +} diff --git a/test/util.h b/test/util.h index 09f94016..8a5cbcc1 100644 --- a/test/util.h +++ b/test/util.h @@ -78,4 +78,4 @@ class date { }; // Returns a locale with the given name if available or classic locale othewise. -std::locale get_locale(const char* name); +std::locale get_locale(const char* name, const char* alt_name = nullptr);