[libcxx-commits] [libcxx] 566868c - [libc++][chrono] Implements formatter weekday.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Tue Oct 18 11:40:11 PDT 2022


Author: Mark de Wever
Date: 2022-10-18T20:40:06+02:00
New Revision: 566868cd825527a82dc6b5753f819cbfff94701c

URL: https://github.com/llvm/llvm-project/commit/566868cd825527a82dc6b5753f819cbfff94701c
DIFF: https://github.com/llvm/llvm-project/commit/566868cd825527a82dc6b5753f819cbfff94701c.diff

LOG: [libc++][chrono] Implements formatter weekday.

Partially implements:
- P1361 Integration of chrono with text formatting
- P2372 Fixing locale handling in chrono formatters

Depends on D134742

Reviewed By: ldionne, #libc

Differential Revision: https://reviews.llvm.org/D136037

Added: 
    libcxx/test/std/time/time.cal/time.cal.weekday/time.cal.weekday.nonmembers/ostream.pass.cpp
    libcxx/test/std/time/time.syn/formatter.weekday.pass.cpp

Modified: 
    libcxx/include/__chrono/convert_to_tm.h
    libcxx/include/__chrono/formatter.h
    libcxx/include/__chrono/ostream.h
    libcxx/include/chrono
    libcxx/test/std/utilities/format/format.formattable/concept.formattable.compile.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h
index 5d34eacc95e75..36801beea2f21 100644
--- 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 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) {
     __result.tm_mon = static_cast<unsigned>(__value) - 1;
   else if constexpr (same_as<_ChronoT, chrono::year>)
     __result.tm_year = static_cast<int>(__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
index 5c0ce2bba4297..89c1e82f426a5 100644
--- 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 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) {
     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 <class _Tp>
+_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 @@ __format_chrono(const _Tp& __value,
       // 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 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::year,
   }
 };
 
+template <__fmt_char_type _CharT>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::weekday, _CharT>
+    : 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
index 36558ca8867de..c48bd6a8b307d 100644
--- 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 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y) {
                            : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y} is not a valid year"), __y));
 }
 
+template <class _CharT, class _Traits>
+_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<unsigned>(__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
index 96dd23b6a62fb..f34919040950b 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -375,6 +375,9 @@ constexpr weekday operator+(const weekday& x, const days&    y) noexcept;
 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<class charT, class traits>
+  basic_ostream<charT, traits>&
+    operator<<(basic_ostream<charT, traits>& os, const weekday& wd);
 
 // 25.8.7, class weekday_indexed    // C++20
 
@@ -634,6 +637,7 @@ namespace std {
   template<class charT> struct formatter<chrono::day, charT>;                     // C++20
   template<class charT> struct formatter<chrono::month, charT>;                   // C++20
   template<class charT> struct formatter<chrono::year, charT>;                    // C++20
+  template<class charT> struct formatter<chrono::weekday, charT>;                 // 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
index 0000000000000..b52293b16d978
--- /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
+
+// <chrono>
+// class weekday;
+
+// template<class charT, class traits>
+//   basic_ostream<charT, traits>&
+//     operator<<(basic_ostream<charT, traits>& os, const weekday& wd);
+
+#include <chrono>
+#include <cassert>
+#include <sstream>
+
+#include "make_string.h"
+#include "platform_support.h" // locale name macros
+#include "test_macros.h"
+
+#define SV(S) MAKE_STRING_VIEW(CharT, S)
+
+template <class CharT>
+static std::basic_string<CharT> stream_c_locale(std::chrono::weekday weekday) {
+  std::basic_stringstream<CharT> sstr;
+  sstr << weekday;
+  return sstr.str();
+}
+
+template <class CharT>
+static std::basic_string<CharT> stream_fr_FR_locale(std::chrono::weekday weekday) {
+  std::basic_stringstream<CharT> sstr;
+  const std::locale locale(LOCALE_fr_FR_UTF_8);
+  sstr.imbue(locale);
+  sstr << weekday;
+  return sstr.str();
+}
+
+template <class CharT>
+static std::basic_string<CharT> stream_ja_JP_locale(std::chrono::weekday weekday) {
+  std::basic_stringstream<CharT> sstr;
+  const std::locale locale(LOCALE_ja_JP_UTF_8);
+  sstr.imbue(locale);
+  sstr << weekday;
+  return sstr.str();
+}
+
+template <class CharT>
+static void test() {
+  assert(stream_c_locale<CharT>(std::chrono::weekday(0)) == SV("Sun"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(1)) == SV("Mon"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(2)) == SV("Tue"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(3)) == SV("Wed"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(4)) == SV("Thu"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(5)) == SV("Fri"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(6)) == SV("Sat"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(7)) == SV("Sun"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(8)) == SV("8 is not a valid weekday"));
+  assert(stream_c_locale<CharT>(std::chrono::weekday(255)) == SV("255 is not a valid weekday"));
+
+#if defined(__APPLE__)
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(0)) == SV("Dim"));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(1)) == SV("Lun"));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(2)) == SV("Mar"));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(3)) == SV("Mer"));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(4)) == SV("Jeu"));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(5)) == SV("Ven"));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(6)) == SV("Sam"));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(7)) == SV("Dim"));
+#else
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(0)) == SV("dim."));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(1)) == SV("lun."));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(2)) == SV("mar."));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(3)) == SV("mer."));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(4)) == SV("jeu."));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(5)) == SV("ven."));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(6)) == SV("sam."));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(7)) == SV("dim."));
+#endif
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(8)) == SV("8 is not a valid weekday"));
+  assert(stream_fr_FR_locale<CharT>(std::chrono::weekday(255)) == SV("255 is not a valid weekday"));
+
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(0)) == SV("日"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(1)) == SV("月"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(2)) == SV("火"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(3)) == SV("水"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(4)) == SV("木"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(5)) == SV("金"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(6)) == SV("土"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(7)) == SV("日"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(8)) == SV("8 is not a valid weekday"));
+  assert(stream_ja_JP_locale<CharT>(std::chrono::weekday(255)) == SV("255 is not a valid weekday"));
+}
+
+int main(int, char**) {
+  test<char>();
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#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
index 0000000000000..6e9dd507843a3
--- /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
+
+// <chrono>
+
+// template<class charT> struct formatter<chrono::weekday, charT>;
+
+#include <chrono>
+#include <format>
+
+#include <cassert>
+#include <concepts>
+#include <locale>
+#include <iostream>
+#include <type_traits>
+
+#include "formatter_tests.h"
+#include "make_string.h"
+#include "platform_support.h" // locale name macros
+#include "test_macros.h"
+
+template <class CharT>
+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 <class CharT>
+static void test_valid_values() {
+  constexpr std::basic_string_view<CharT> 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<CharT> 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 
diff erent 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 <class CharT>
+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<CharT> fmt  = SV("{:%%u='%u'%t%%Ou='%Ou'%t%%w='%w'%t%%Ow='%Ow'%n}");
+  constexpr std::basic_string_view<CharT> 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 
diff erent 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 
diff erent 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 
diff erent 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 <class CharT>
+static void test() {
+  test_no_chrono_specs<CharT>();
+  test_valid_values<CharT>();
+  test_invalid_values<CharT>();
+  check_invalid_types<CharT>(
+      {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<char>();
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#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
index 7d7f3e83e054a..8f83ad6f771b9 100644
--- 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 @@ void test_P1361() {
   assert_is_formattable<std::chrono::month, CharT>();
   assert_is_formattable<std::chrono::year, CharT>();
 
-  assert_is_not_formattable<std::chrono::weekday, CharT>();
+  assert_is_formattable<std::chrono::weekday, CharT>();
   assert_is_not_formattable<std::chrono::weekday_indexed, CharT>();
   assert_is_not_formattable<std::chrono::weekday_last, CharT>();
 


        


More information about the libcxx-commits mailing list