diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h --- a/libcxx/include/__chrono/convert_to_tm.h +++ b/libcxx/include/__chrono/convert_to_tm.h @@ -13,6 +13,7 @@ #include <__chrono/day.h> #include <__chrono/duration.h> #include <__chrono/month.h> +#include <__chrono/weekday.h> #include <__chrono/year.h> #include <__concepts/same_as.h> #include <__config> @@ -52,6 +53,8 @@ __result.tm_mon = static_cast(__value) - 1; else if constexpr (same_as<_ChronoT, chrono::year>) __result.tm_year = static_cast(__value) - 1900; + else if constexpr (same_as<_ChronoCalendarTimePoint, chrono::weekday>) + __result.tm_wday = __value.c_encoding(); else static_assert(sizeof(_ChronoT) == 0, "Add the missing type specialization"); diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h --- a/libcxx/include/__chrono/formatter.h +++ b/libcxx/include/__chrono/formatter.h @@ -19,6 +19,7 @@ #include <__chrono/parser_std_format_spec.h> #include <__chrono/statically_widen.h> #include <__chrono/time_point.h> +#include <__chrono/weekday.h> #include <__chrono/year.h> #include <__concepts/arithmetic.h> #include <__concepts/same_as.h> @@ -282,6 +283,22 @@ return __value.ok(); else if constexpr (same_as<_Tp, chrono::year>) return true; + else if constexpr (same_as<_Tp, chrono::weekday>) + return true; + else + static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) { + if constexpr (same_as<_Tp, chrono::day>) + return true; + else if constexpr (same_as<_Tp, chrono::month>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday>) + return __value.ok(); else static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); } @@ -314,6 +331,9 @@ // Note that the behaviour what the precision does isn't specified. __specs.__precision_ = -1; } else { + if (__specs.__chrono_.__weekday_name_ && !__formatter::__weekday_name_ok(__value)) + std::__throw_format_error("formatting a weekday name needs a valid weekday"); + if (__specs.__chrono_.__month_name_ && !__formatter::__month_name_ok(__value)) std::__throw_format_error("formatting a month name from an invalid month number"); @@ -404,6 +424,18 @@ } }; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter + : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx) + -> decltype(__parse_ctx.begin()) { + return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); + } +}; + #endif // if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h --- a/libcxx/include/__chrono/ostream.h +++ b/libcxx/include/__chrono/ostream.h @@ -14,6 +14,7 @@ #include <__chrono/duration.h> #include <__chrono/month.h> #include <__chrono/statically_widen.h> +#include <__chrono/weekday.h> #include <__chrono/year.h> #include <__concepts/same_as.h> #include <__config> @@ -126,6 +127,15 @@ : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y} is not a valid year"), __y)); } +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd) { + return __os << (__wd.ok() ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%a}"), __wd) + : std::format(__os.getloc(), // TODO FMT Standard mandated locale isn't used. + _LIBCPP_STATICALLY_WIDEN(_CharT, "{} is not a valid weekday"), + static_cast(__wd.c_encoding()))); +} + } // namespace chrono #endif //if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) diff --git a/libcxx/include/chrono b/libcxx/include/chrono --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -375,6 +375,9 @@ constexpr weekday operator+(const days& x, const weekday& y) noexcept; constexpr weekday operator-(const weekday& x, const days& y) noexcept; constexpr days operator-(const weekday& x, const weekday& y) noexcept; +template + basic_ostream& + operator<<(basic_ostream& os, const weekday& wd); // 25.8.7, class weekday_indexed // C++20 @@ -634,6 +637,7 @@ template struct formatter; // C++20 template struct formatter; // C++20 template struct formatter; // C++20 + template struct formatter; // C++20 } // namespace std namespace chrono { diff --git a/libcxx/test/std/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/ostream.pass.cpp b/libcxx/test/std/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/ostream.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/ostream.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: no-localization +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// +// class weekday; + +// template +// basic_ostream& +// operator<<(basic_ostream& os, const weekday& wd); + +#include +#include +#include + +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +static std::basic_string stream_c_locale(std::chrono::weekday weekday) { + std::basic_stringstream sstr; + sstr << weekday; + return sstr.str(); +} + +template +static std::basic_string stream_fr_FR_locale(std::chrono::weekday weekday) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_fr_FR_UTF_8); + sstr.imbue(locale); + sstr << weekday; + return sstr.str(); +} + +template +static std::basic_string stream_ja_JP_locale(std::chrono::weekday weekday) { + std::basic_stringstream sstr; + const std::locale locale(LOCALE_ja_JP_UTF_8); + sstr.imbue(locale); + sstr << weekday; + return sstr.str(); +} + +template +static void test() { + assert(stream_c_locale(std::chrono::weekday(0)) == SV("Sun")); + assert(stream_c_locale(std::chrono::weekday(1)) == SV("Mon")); + assert(stream_c_locale(std::chrono::weekday(2)) == SV("Tue")); + assert(stream_c_locale(std::chrono::weekday(3)) == SV("Wed")); + assert(stream_c_locale(std::chrono::weekday(4)) == SV("Thu")); + assert(stream_c_locale(std::chrono::weekday(5)) == SV("Fri")); + assert(stream_c_locale(std::chrono::weekday(6)) == SV("Sat")); + assert(stream_c_locale(std::chrono::weekday(7)) == SV("Sun")); + assert(stream_c_locale(std::chrono::weekday(8)) == SV("8 is not a valid weekday")); + assert(stream_c_locale(std::chrono::weekday(255)) == SV("255 is not a valid weekday")); + +#if defined(__APPLE__) + assert(stream_fr_FR_locale(std::chrono::weekday(0)) == SV("Dim")); + assert(stream_fr_FR_locale(std::chrono::weekday(1)) == SV("Lun")); + assert(stream_fr_FR_locale(std::chrono::weekday(2)) == SV("Mar")); + assert(stream_fr_FR_locale(std::chrono::weekday(3)) == SV("Mer")); + assert(stream_fr_FR_locale(std::chrono::weekday(4)) == SV("Jeu")); + assert(stream_fr_FR_locale(std::chrono::weekday(5)) == SV("Ven")); + assert(stream_fr_FR_locale(std::chrono::weekday(6)) == SV("Sam")); + assert(stream_fr_FR_locale(std::chrono::weekday(7)) == SV("Dim")); +#else + assert(stream_fr_FR_locale(std::chrono::weekday(0)) == SV("dim.")); + assert(stream_fr_FR_locale(std::chrono::weekday(1)) == SV("lun.")); + assert(stream_fr_FR_locale(std::chrono::weekday(2)) == SV("mar.")); + assert(stream_fr_FR_locale(std::chrono::weekday(3)) == SV("mer.")); + assert(stream_fr_FR_locale(std::chrono::weekday(4)) == SV("jeu.")); + assert(stream_fr_FR_locale(std::chrono::weekday(5)) == SV("ven.")); + assert(stream_fr_FR_locale(std::chrono::weekday(6)) == SV("sam.")); + assert(stream_fr_FR_locale(std::chrono::weekday(7)) == SV("dim.")); +#endif + assert(stream_fr_FR_locale(std::chrono::weekday(8)) == SV("8 is not a valid weekday")); + assert(stream_fr_FR_locale(std::chrono::weekday(255)) == SV("255 is not a valid weekday")); + + assert(stream_ja_JP_locale(std::chrono::weekday(0)) == SV("日")); + assert(stream_ja_JP_locale(std::chrono::weekday(1)) == SV("月")); + assert(stream_ja_JP_locale(std::chrono::weekday(2)) == SV("火")); + assert(stream_ja_JP_locale(std::chrono::weekday(3)) == SV("水")); + assert(stream_ja_JP_locale(std::chrono::weekday(4)) == SV("木")); + assert(stream_ja_JP_locale(std::chrono::weekday(5)) == SV("金")); + assert(stream_ja_JP_locale(std::chrono::weekday(6)) == SV("土")); + assert(stream_ja_JP_locale(std::chrono::weekday(7)) == SV("日")); + assert(stream_ja_JP_locale(std::chrono::weekday(8)) == SV("8 is not a valid weekday")); + assert(stream_ja_JP_locale(std::chrono::weekday(255)) == SV("255 is not a valid weekday")); +} + +int main(int, char**) { + test(); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/libcxx/test/std/time/time.syn/formatter.weekday.pass.cpp b/libcxx/test/std/time/time.syn/formatter.weekday.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/time/time.syn/formatter.weekday.pass.cpp @@ -0,0 +1,196 @@ +//===----------------------------------------------------------------------===// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: no-localization +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// TODO FMT Investigate Windows issues. +// UNSUPPORTED: msvc, target={{.+}}-windows-gnu + +// REQUIRES: locale.fr_FR.UTF-8 +// REQUIRES: locale.ja_JP.UTF-8 + +// + +// template struct formatter; + +#include +#include + +#include +#include +#include +#include +#include + +#include "formatter_tests.h" +#include "make_string.h" +#include "platform_support.h" // locale name macros +#include "test_macros.h" + +template +static void test_no_chrono_specs() { + using namespace std::literals::chrono_literals; + + // Valid day + check(SV("Sun"), SV("{}"), std::chrono::weekday(0)); + + // Invalid day + check(SV("8 is not a valid weekday"), SV("{}"), std::chrono::weekday(8)); +} + +template +static void test_valid_values() { + constexpr std::basic_string_view fmt = + SV("{:%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%t%%a='%a'%t%%A='%A'%n}"); + constexpr std::basic_string_view lfmt = + SV("{:L%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%t%%a='%a'%t%%A='%A'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + + // Non localized output using C-locale + check(SV("%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\t%a='Sun'\t%A='Sunday'\n"), fmt, std::chrono::weekday(0)); + check(SV("%u='1'\t%Ou='1'\t%w='1'\t%Ow='1'\t%a='Mon'\t%A='Monday'\n"), fmt, std::chrono::weekday(1)); + check(SV("%u='2'\t%Ou='2'\t%w='2'\t%Ow='2'\t%a='Tue'\t%A='Tuesday'\n"), fmt, std::chrono::weekday(2)); + check(SV("%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\t%a='Wed'\t%A='Wednesday'\n"), fmt, std::chrono::weekday(3)); + check(SV("%u='4'\t%Ou='4'\t%w='4'\t%Ow='4'\t%a='Thu'\t%A='Thursday'\n"), fmt, std::chrono::weekday(4)); + check(SV("%u='5'\t%Ou='5'\t%w='5'\t%Ow='5'\t%a='Fri'\t%A='Friday'\n"), fmt, std::chrono::weekday(5)); + check(SV("%u='6'\t%Ou='6'\t%w='6'\t%Ow='6'\t%a='Sat'\t%A='Saturday'\n"), fmt, std::chrono::weekday(6)); + check(SV("%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\t%a='Sun'\t%A='Sunday'\n"), fmt, std::chrono::weekday(7)); + +#if defined(__APPLE__) + // Use the global locale (fr_FR) + check(SV("%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\t%a='Dim'\t%A='Dimanche'\n"), lfmt, std::chrono::weekday(0)); + check(SV("%u='1'\t%Ou='1'\t%w='1'\t%Ow='1'\t%a='Lun'\t%A='Lundi'\n"), lfmt, std::chrono::weekday(1)); + check(SV("%u='2'\t%Ou='2'\t%w='2'\t%Ow='2'\t%a='Mar'\t%A='Mardi'\n"), lfmt, std::chrono::weekday(2)); + check(SV("%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\t%a='Mer'\t%A='Mercredi'\n"), lfmt, std::chrono::weekday(3)); + check(SV("%u='4'\t%Ou='4'\t%w='4'\t%Ow='4'\t%a='Jeu'\t%A='Jeudi'\n"), lfmt, std::chrono::weekday(4)); + check(SV("%u='5'\t%Ou='5'\t%w='5'\t%Ow='5'\t%a='Ven'\t%A='Vendredi'\n"), lfmt, std::chrono::weekday(5)); + check(SV("%u='6'\t%Ou='6'\t%w='6'\t%Ow='6'\t%a='Sam'\t%A='Samedi'\n"), lfmt, std::chrono::weekday(6)); + check(SV("%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\t%a='Dim'\t%A='Dimanche'\n"), lfmt, std::chrono::weekday(7)); +#else + // Use the global locale (fr_FR) + check(SV("%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\t%a='dim.'\t%A='dimanche'\n"), lfmt, std::chrono::weekday(0)); + check(SV("%u='1'\t%Ou='1'\t%w='1'\t%Ow='1'\t%a='lun.'\t%A='lundi'\n"), lfmt, std::chrono::weekday(1)); + check(SV("%u='2'\t%Ou='2'\t%w='2'\t%Ow='2'\t%a='mar.'\t%A='mardi'\n"), lfmt, std::chrono::weekday(2)); + check(SV("%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\t%a='mer.'\t%A='mercredi'\n"), lfmt, std::chrono::weekday(3)); + check(SV("%u='4'\t%Ou='4'\t%w='4'\t%Ow='4'\t%a='jeu.'\t%A='jeudi'\n"), lfmt, std::chrono::weekday(4)); + check(SV("%u='5'\t%Ou='5'\t%w='5'\t%Ow='5'\t%a='ven.'\t%A='vendredi'\n"), lfmt, std::chrono::weekday(5)); + check(SV("%u='6'\t%Ou='6'\t%w='6'\t%Ow='6'\t%a='sam.'\t%A='samedi'\n"), lfmt, std::chrono::weekday(6)); + check(SV("%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\t%a='dim.'\t%A='dimanche'\n"), lfmt, std::chrono::weekday(7)); +#endif + + // Use supplied locale (ja_JP). + // This locale has a different alternate, but not on all platforms +#if defined(_WIN32) || defined(__APPLE__) || defined(_AIX) + check(loc, SV("%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\t%a='日'\t%A='日曜日'\n"), lfmt, std::chrono::weekday(0)); + check(loc, SV("%u='1'\t%Ou='1'\t%w='1'\t%Ow='1'\t%a='月'\t%A='月曜日'\n"), lfmt, std::chrono::weekday(1)); + check(loc, SV("%u='2'\t%Ou='2'\t%w='2'\t%Ow='2'\t%a='火'\t%A='火曜日'\n"), lfmt, std::chrono::weekday(2)); + check(loc, SV("%u='3'\t%Ou='3'\t%w='3'\t%Ow='3'\t%a='水'\t%A='水曜日'\n"), lfmt, std::chrono::weekday(3)); + check(loc, SV("%u='4'\t%Ou='4'\t%w='4'\t%Ow='4'\t%a='木'\t%A='木曜日'\n"), lfmt, std::chrono::weekday(4)); + check(loc, SV("%u='5'\t%Ou='5'\t%w='5'\t%Ow='5'\t%a='金'\t%A='金曜日'\n"), lfmt, std::chrono::weekday(5)); + check(loc, SV("%u='6'\t%Ou='6'\t%w='6'\t%Ow='6'\t%a='土'\t%A='土曜日'\n"), lfmt, std::chrono::weekday(6)); + check(loc, SV("%u='7'\t%Ou='7'\t%w='0'\t%Ow='0'\t%a='日'\t%A='日曜日'\n"), lfmt, std::chrono::weekday(7)); +#else + check(loc, SV("%u='7'\t%Ou='七'\t%w='0'\t%Ow='〇'\t%a='日'\t%A='日曜日'\n"), lfmt, std::chrono::weekday(0)); + check(loc, SV("%u='1'\t%Ou='一'\t%w='1'\t%Ow='一'\t%a='月'\t%A='月曜日'\n"), lfmt, std::chrono::weekday(1)); + check(loc, SV("%u='2'\t%Ou='二'\t%w='2'\t%Ow='二'\t%a='火'\t%A='火曜日'\n"), lfmt, std::chrono::weekday(2)); + check(loc, SV("%u='3'\t%Ou='三'\t%w='3'\t%Ow='三'\t%a='水'\t%A='水曜日'\n"), lfmt, std::chrono::weekday(3)); + check(loc, SV("%u='4'\t%Ou='四'\t%w='4'\t%Ow='四'\t%a='木'\t%A='木曜日'\n"), lfmt, std::chrono::weekday(4)); + check(loc, SV("%u='5'\t%Ou='五'\t%w='5'\t%Ow='五'\t%a='金'\t%A='金曜日'\n"), lfmt, std::chrono::weekday(5)); + check(loc, SV("%u='6'\t%Ou='六'\t%w='6'\t%Ow='六'\t%a='土'\t%A='土曜日'\n"), lfmt, std::chrono::weekday(6)); + check(loc, SV("%u='7'\t%Ou='七'\t%w='0'\t%Ow='〇'\t%a='日'\t%A='日曜日'\n"), lfmt, std::chrono::weekday(7)); +#endif + + std::locale::global(std::locale::classic()); +} + +template +static void test_invalid_values() { + // Test that %a and %A throw an exception. + check_exception("formatting a weekday name needs a valid weekday", SV("{:%a}"), std::chrono::weekday(8)); + check_exception("formatting a weekday name needs a valid weekday", SV("{:%a}"), std::chrono::weekday(255)); + check_exception("formatting a weekday name needs a valid weekday", SV("{:%A}"), std::chrono::weekday(8)); + check_exception("formatting a weekday name needs a valid weekday", SV("{:%A}"), std::chrono::weekday(255)); + + constexpr std::basic_string_view fmt = SV("{:%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}"); + constexpr std::basic_string_view lfmt = SV("{:L%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}"); + + const std::locale loc(LOCALE_ja_JP_UTF_8); + std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); + +#if defined(__APPLE__) + // Non localized output using C-locale + check(SV("%u='8'\t%Ou='8'\t%w='8'\t%Ow='8'\n"), fmt, std::chrono::weekday(8)); + check(SV("%u='255'\t%Ou='255'\t%w='255'\t%Ow='255'\n"), fmt, std::chrono::weekday(255)); + + // Use the global locale (fr_FR) + check(SV("%u='8'\t%Ou='8'\t%w='8'\t%Ow='8'\n"), lfmt, std::chrono::weekday(8)); + check(SV("%u='255'\t%Ou='255'\t%w='255'\t%Ow='255'\n"), lfmt, std::chrono::weekday(255)); + + // Use supplied locale (ja_JP). This locale has a different alternate. + check(loc, SV("%u='8'\t%Ou='8'\t%w='8'\t%Ow='8'\n"), lfmt, std::chrono::weekday(8)); + check(loc, SV("%u='255'\t%Ou='255'\t%w='255'\t%Ow='255'\n"), lfmt, std::chrono::weekday(255)); +#elif defined(_AIX) + // Non localized output using C-locale + check(SV("%u='8'\t%Ou='8'\t%w='8'\t%Ow='8'\n"), fmt, std::chrono::weekday(8)); + check(SV("%u='5'\t%Ou='5'\t%w='5'\t%Ow='5'\n"), fmt, std::chrono::weekday(255)); + + // Use the global locale (fr_FR) + check(SV("%u='8'\t%Ou='8'\t%w='8'\t%Ow='8'\n"), lfmt, std::chrono::weekday(8)); + check(SV("%u='5'\t%Ou='5'\t%w='5'\t%Ow='5'\n"), lfmt, std::chrono::weekday(255)); + + // Use supplied locale (ja_JP). This locale has a different alternate. + check(loc, SV("%u='8'\t%Ou='8'\t%w='8'\t%Ow='8'\n"), lfmt, std::chrono::weekday(8)); + check(loc, SV("%u='5'\t%Ou='5'\t%w='5'\t%Ow='5'\n"), lfmt, std::chrono::weekday(255)); +#else + // Non localized output using C-locale + check(SV("%u='1'\t%Ou='1'\t%w='8'\t%Ow='8'\n"), fmt, std::chrono::weekday(8)); + check(SV("%u='3'\t%Ou='3'\t%w='255'\t%Ow='255'\n"), fmt, std::chrono::weekday(255)); + + // Use the global locale (fr_FR) + check(SV("%u='1'\t%Ou='1'\t%w='8'\t%Ow='8'\n"), lfmt, std::chrono::weekday(8)); + check(SV("%u='3'\t%Ou='3'\t%w='255'\t%Ow='255'\n"), lfmt, std::chrono::weekday(255)); + + // Use supplied locale (ja_JP). This locale has a different alternate. + check(loc, SV("%u='1'\t%Ou='一'\t%w='8'\t%Ow='八'\n"), lfmt, std::chrono::weekday(8)); + check(loc, SV("%u='3'\t%Ou='三'\t%w='255'\t%Ow='255'\n"), lfmt, std::chrono::weekday(255)); + +#endif + + std::locale::global(std::locale::classic()); +} + +template +static void test() { + test_no_chrono_specs(); + test_valid_values(); + test_invalid_values(); + check_invalid_types( + {SV("a"), SV("A"), SV("t"), SV("u"), SV("w"), SV("Ou"), SV("Ow")}, std::chrono::weekday(0)); + + check_exception("Expected '%' or '}' in the chrono format-string", SV("{:A"), std::chrono::weekday(0)); + check_exception("The chrono-specs contains a '{'", SV("{:%%{"), std::chrono::weekday(0)); + check_exception("End of input while parsing the modifier chrono conversion-spec", SV("{:%"), std::chrono::weekday(0)); + check_exception("End of input while parsing the modifier E", SV("{:%E"), std::chrono::weekday(0)); + check_exception("End of input while parsing the modifier O", SV("{:%O"), std::chrono::weekday(0)); + + // Precision not allowed + check_exception("Expected '%' or '}' in the chrono format-string", SV("{:.3}"), std::chrono::weekday(0)); +} + +int main(int, char**) { + test(); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp --- a/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp +++ b/libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp @@ -143,7 +143,7 @@ assert_is_formattable(); assert_is_formattable(); - assert_is_not_formattable(); + assert_is_formattable(); assert_is_not_formattable(); assert_is_not_formattable();