diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
index 82f2d39ec44..9f5b9e13a82 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -210,6 +210,20 @@ namespace __format
     struct _ChronoSpec : _Spec<_CharT>
     {
       basic_string_view<_CharT> _M_chrono_specs;
+
+      // Use one of the reserved bits in __format::_Spec<C>.
+      // This indicates that a locale-dependent conversion specifier such as
+      // %a is used in the chrono-specs. This is not the same as the
+      // _Spec<C>::_M_localized member which indicates that "L" was present
+      // in the format-spec, e.g. "{:L%a}" is localized and locale-specific,
+      // but "{:L}" is only localized and "{:%a}" is only locale-specific.
+      constexpr bool
+      _M_locale_specific() const noexcept
+      { return this->_M_reserved & 1; }
+
+      constexpr void
+      _M_locale_specific(bool __b) noexcept
+      { this->_M_reserved |= __b; }
     };
 
   // Represents the information provided by a chrono type.
@@ -304,11 +318,12 @@ namespace __format
 	  const auto __chrono_specs = __first++; // Skip leading '%'
 	  if (*__chrono_specs != '%')
 	    __throw_format_error("chrono format error: no '%' at start of "
-				     "chrono-specs");
+				 "chrono-specs");
 
 	  _CharT __mod{};
 	  bool __conv = true;
 	  int __needed = 0;
+	  bool __locale_specific = false;
 
 	  while (__first != __last)
 	    {
@@ -321,15 +336,18 @@ namespace __format
 		case 'a':
 		case 'A':
 		  __needed = _Weekday;
+		  __locale_specific = true;
 		  break;
 		case 'b':
 		case 'h':
 		case 'B':
 		  __needed = _Month;
+		  __locale_specific = true;
 		  break;
 		case 'c':
 		  __needed = _DateTime;
 		  __allowed_mods = _Mod_E;
+		  __locale_specific = true;
 		  break;
 		case 'C':
 		  __needed = _Year;
@@ -367,6 +385,8 @@ namespace __format
 		  break;
 		case 'p':
 		case 'r':
+		  __locale_specific = true;
+		  [[fallthrough]];
 		case 'R':
 		case 'T':
 		  __needed = _TimeOfDay;
@@ -392,10 +412,12 @@ namespace __format
 		  break;
 		case 'x':
 		  __needed = _Date;
+		  __locale_specific = true;
 		  __allowed_mods = _Mod_E;
 		  break;
 		case 'X':
 		  __needed = _TimeOfDay;
+		  __locale_specific = true;
 		  __allowed_mods = _Mod_E;
 		  break;
 		case 'y':
@@ -435,6 +457,8 @@ namespace __format
 		    || (__mod == 'O' && !(__allowed_mods & _Mod_O)))
 		__throw_format_error("chrono format error: invalid "
 				     " modifier in chrono-specs");
+	      if (__mod && __c != 'z')
+		__locale_specific = true;
 	      __mod = _CharT();
 
 	      if ((__parts & __needed) != __needed)
@@ -466,6 +490,7 @@ namespace __format
 	  _M_spec = __spec;
 	  _M_spec._M_chrono_specs
 		 = __string_view(__chrono_specs, __first - __chrono_specs);
+	  _M_spec._M_locale_specific(__locale_specific);
 
 	  return __first;
 	}
@@ -485,6 +510,26 @@ namespace __format
 	  if (__first == __last)
 	    return _M_format_to_ostream(__t, __fc, __is_neg);
 
+#if __glibcxx_format >= 202207L // C++ >= 23
+#if _GLIBCXX_USE_CXX11_ABI
+	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	  // 3565. Handling of encodings in localized formatting
+	  //       of chrono types is underspecified
+	  if constexpr (is_same_v<_CharT, char>)
+	    if constexpr (__unicode::__literal_encoding_is_utf8())
+	      if (_M_spec._M_localized && _M_spec._M_locale_specific())
+		{
+		  extern locale __with_encoding_conversion(const locale&);
+
+		  // Allocate and cache the necessary state to convert strings
+		  // in the locale's encoding to UTF-8.
+		  locale __loc = __fc.locale();
+		  if (__loc != locale::classic())
+		    __fc._M_loc =  __with_encoding_conversion(__loc);
+		}
+#endif
+#endif
+
 	  _Sink_iter<_CharT> __out;
 	  __format::_Str_sink<_CharT> __sink;
 	  bool __write_direct = false;
@@ -741,6 +786,37 @@ namespace __format
       static constexpr _CharT _S_space = _S_chars[14];
       static constexpr const _CharT* _S_empty_spec = _S_chars + 15;
 
+      template<typename _OutIter>
+	_OutIter
+	_M_write(_OutIter __out, const locale& __loc, __string_view __s) const
+	{
+	  // FIXME: It would be nice to treat this as a DR for C++20
+	  // but it currently requires new symbols in libstdc++exp.a
+	  // which we don't want to require for C++20. Could do it when
+	  // those symbols move into the non-experimental library.
+#if __glibcxx_format >= 202207L // C++ >= 23
+#if _GLIBCXX_USE_CXX11_ABI
+	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	  // 3565. Handling of encodings in localized formatting
+	  //       of chrono types is underspecified
+	  using _StringType = string;
+	  string __buf;
+	  if constexpr (is_same_v<_CharT, char>)
+	    if constexpr (__unicode::__literal_encoding_is_utf8())
+	      if (_M_spec._M_localized && _M_spec._M_locale_specific()
+		    && __loc != locale::classic())
+		{
+		  extern string_view
+		  __locale_encoding_to_utf8(const std::locale&, string_view,
+					    _StringType&);
+
+		  __s = __locale_encoding_to_utf8(__loc, __s, __buf);
+		}
+#endif
+#endif
+	  return __format::__write(std::move(__out), __s);
+	}
+
       template<typename _Tp, typename _FormatContext>
 	typename _FormatContext::iterator
 	_M_a_A(const _Tp& __t, typename _FormatContext::iterator __out,
@@ -760,7 +836,7 @@ namespace __format
 	  else
 	    __tp._M_days_abbreviated(__days);
 	  __string_view __str(__days[__wd.c_encoding()]);
-	  return __format::__write(std::move(__out), __str);
+	  return _M_write(std::move(__out), __loc, __str);
 	}
 
       template<typename _Tp, typename _FormatContext>
@@ -781,7 +857,7 @@ namespace __format
 	  else
 	    __tp._M_months_abbreviated(__months);
 	  __string_view __str(__months[(unsigned)__m - 1]);
-	  return __format::__write(std::move(__out), __str);
+	  return _M_write(std::move(__out), __loc, __str);
 	}
 
       template<typename _Tp, typename _FormatContext>
@@ -1058,8 +1134,8 @@ namespace __format
 	  const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
 	  const _CharT* __ampm[2];
 	  __tp._M_am_pm(__ampm);
-	  return std::format_to(std::move(__out), _S_empty_spec,
-				__ampm[__hms.hours().count() >= 12]);
+	  return _M_write(std::move(__out), __loc,
+			  __ampm[__hms.hours().count() >= 12]);
 	}
 
       template<typename _Tp, typename _FormatContext>
@@ -1094,8 +1170,9 @@ namespace __format
 	  basic_string<_CharT> __fmt(_S_empty_spec);
 	  __fmt.insert(1u, 1u, _S_colon);
 	  __fmt.insert(2u, __ampm_fmt);
-	  return std::vformat_to(std::move(__out), __fmt,
-				 std::make_format_args<_FormatContext>(__t));
+	  using _FmtStr = _Runtime_format_string<_CharT>;
+	  return _M_write(std::move(__out), __loc,
+			  std::format(__loc, _FmtStr(__fmt), __t));
 	}
 
       template<typename _Tp, typename _FormatContext>
@@ -1278,8 +1355,9 @@ namespace __format
 	  basic_string<_CharT> __fmt(_S_empty_spec);
 	  __fmt.insert(1u, 1u, _S_colon);
 	  __fmt.insert(2u, __rep);
-	  return std::vformat_to(std::move(__out), __fmt,
-				 std::make_format_args<_FormatContext>(__t));
+	  using _FmtStr = _Runtime_format_string<_CharT>;
+	  return _M_write(std::move(__out), __loc,
+			  std::format(__loc, _FmtStr(__fmt), __t));
 	}
 
       template<typename _Tp, typename _FormatContext>
@@ -1301,8 +1379,9 @@ namespace __format
 	  basic_string<_CharT> __fmt(_S_empty_spec);
 	  __fmt.insert(1u, 1u, _S_colon);
 	  __fmt.insert(2u, __rep);
-	  return std::vformat_to(std::move(__out), __fmt,
-				 std::make_format_args<_FormatContext>(__t));
+	  using _FmtStr = _Runtime_format_string<_CharT>;
+	  return _M_write(std::move(__out), __loc,
+			  std::format(__loc, _FmtStr(__fmt), __t));
 	}
 
       template<typename _Tp, typename _FormatContext>
@@ -1579,7 +1658,7 @@ namespace __format
 	  const auto& __tp = use_facet<time_put<_CharT>>(__loc);
 	  __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
 	  if (__os)
-	    __out = __format::__write(std::move(__out), __os.view());
+	    __out = _M_write(std::move(__out), __loc, __os.view());
 	  return __out;
 	}
     };
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 8fb8a2877ee..29ca973fe43 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1160,14 +1160,25 @@ ftms = {
 };
 
 ftms = {
+  name = format;
+  // 202311 P2918R2 Runtime format strings II
+  // values = {
+    // v = 202311;
+    // cxxmin = 26;
+    // hosted = yes;
+  // };
+  // 202207 Encodings in localized formatting of chrono, basic-format-string.
+  // 202304 P2510R3 Formatting pointers
+  // 202305 P2757R3 Type checking format args
+  // 202306 P2637R3 Member visit
+  values = {
+    v = 202304;
+    cxxmin = 23;
+    hosted = yes;
+  };
   // 201907 Text Formatting, Integration of chrono, printf corner cases.
   // 202106 std::format improvements.
   // 202110 Fixing locale handling in chrono formatters, generator-like types.
-  // 202207 Encodings in localized formatting of chrono, basic-format-string.
-  // 202207 P2286R8 Formatting Ranges
-  // 202207 P2585R1 Improving default container formatting
-  // TODO: #define __cpp_lib_format_ranges 202207L
-  name = format;
   values = {
     v = 202110;
     cxxmin = 20;
@@ -1364,6 +1375,19 @@ ftms = {
   };
 };
 
+// ftms = {
+  // name = format_ranges;
+  // 202207 P2286R8 Formatting Ranges
+  // 202207 P2585R1 Improving default container formatting
+  // LWG3750 Too many papers bump __cpp_lib_format
+  // TODO: #define __cpp_lib_format_ranges 202207L
+  // values = {
+    // v = 202207;
+    // cxxmin = 23;
+    // hosted = yes;
+  // };
+// };
+
 ftms = {
   name = freestanding_algorithm;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index fa4e89cf845..714bf064950 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1304,7 +1304,12 @@
 #undef __glibcxx_want_barrier
 
 #if !defined(__cpp_lib_format)
-# if (__cplusplus >= 202002L) && _GLIBCXX_HOSTED
+# if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
+#  define __glibcxx_format 202304L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_format)
+#   define __cpp_lib_format 202304L
+#  endif
+# elif (__cplusplus >= 202002L) && _GLIBCXX_HOSTED
 #  define __glibcxx_format 202110L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_format)
 #   define __cpp_lib_format 202110L
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 6c958bc11a5..1f72cb9b9ff 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -2341,10 +2341,10 @@ namespace __format
 
 // _GLIBCXX_RESOLVE_LIB_DEFECTS
 // P2510R3 Formatting pointers
-#if __cplusplus > 202302L || ! defined __STRICT_ANSI__
-#define _GLIBCXX_P2518R3 1
+#if __glibcxx_format >= 202304L || ! defined __STRICT_ANSI__
+# define _GLIBCXX_P2518R3 1
 #else
-#define _GLIBCXX_P2518R3 0
+# define _GLIBCXX_P2518R3 0
 #endif
 
 #if _GLIBCXX_P2518R3
@@ -3788,6 +3788,9 @@ namespace __format
     __do_vformat_to(_Out, basic_string_view<_CharT>,
 		    const basic_format_args<_Context>&,
 		    const locale* = nullptr);
+
+  template<typename _CharT> struct __formatter_chrono;
+
 } // namespace __format
 /// @endcond
 
@@ -3798,6 +3801,11 @@ namespace __format
    * this class template explicitly. For typical uses of `std::format` the
    * library will use the specializations `std::format_context` (for `char`)
    * and `std::wformat_context` (for `wchar_t`).
+   *
+   * You are not allowed to define partial or explicit specializations of
+   * this class template.
+   *
+   * @since C++20
    */
   template<typename _Out, typename _CharT>
     class basic_format_context
@@ -3824,6 +3832,8 @@ namespace __format
 				  const basic_format_args<_Context2>&,
 				  const locale*);
 
+      friend __format::__formatter_chrono<_CharT>;
+
     public:
       basic_format_context() = default;
       ~basic_format_context() = default;
diff --git a/libstdc++-v3/src/c++26/Makefile.am b/libstdc++-v3/src/c++26/Makefile.am
index 000ced1f501..1f9dff7e737 100644
--- a/libstdc++-v3/src/c++26/Makefile.am
+++ b/libstdc++-v3/src/c++26/Makefile.am
@@ -46,6 +46,12 @@ else
 libc__26convenience_la_SOURCES =
 endif
 
+# This needs access to the internals of std::locale.
+text_encoding.lo: text_encoding.cc
+	$(LTCXXCOMPILE) -fno-access-control -c $<
+text_encoding.o: text_encoding.cc
+	$(CXXCOMPILE) -fno-access-control -c $<
+
 # AM_CXXFLAGS needs to be in each subdirectory so that it can be
 # modified in a per-library or per-sub-library way.  Need to manually
 # set this option because CONFIG_CXXFLAGS has to be after
diff --git a/libstdc++-v3/src/c++26/Makefile.in b/libstdc++-v3/src/c++26/Makefile.in
index 77e73b2b265..96947ccdd0c 100644
--- a/libstdc++-v3/src/c++26/Makefile.in
+++ b/libstdc++-v3/src/c++26/Makefile.in
@@ -742,6 +742,12 @@ uninstall-am:
 
 vpath % $(top_srcdir)/src/c++26
 
+# This needs access to the internals of std::locale.
+text_encoding.lo: text_encoding.cc
+	$(LTCXXCOMPILE) -fno-access-control -c $<
+text_encoding.o: text_encoding.cc
+	$(CXXCOMPILE) -fno-access-control -c $<
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/libstdc++-v3/src/c++26/text_encoding.cc b/libstdc++-v3/src/c++26/text_encoding.cc
index b9a50ef1a00..fc5141e02c7 100644
--- a/libstdc++-v3/src/c++26/text_encoding.cc
+++ b/libstdc++-v3/src/c++26/text_encoding.cc
@@ -26,17 +26,28 @@
 #include <locale>
 
 #ifdef _GLIBCXX_USE_NL_LANGINFO_L
+#include <memory>   // make_unique
+#include <string.h> // strlen, strcpy
 #include <locale.h>
 #if __has_include(<xlocale.h>)
 # include <xlocale.h>
 #endif
 #include <langinfo.h>
 
+#ifdef _GLIBCXX_HAVE_ICONV
+# include <format>
+# include <chrono>
+# include <iconv.h>
+# include <errno.h>
+#endif
+
 #if __CHAR_BIT__ == 8
 namespace std
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
-
+namespace
+{
+// Attempt to determine the text_encoding used by the named locale.
 text_encoding
 __locale_encoding(const char* name)
 {
@@ -54,6 +65,48 @@ __locale_encoding(const char* name)
   return enc;
 }
 
+// A non-standard locale::facet that caches the locale's std::text_encoding
+// and an iconv descriptor for converting from that encoding to UTF-8.
+struct __encoding : locale::facet
+{
+  static locale::id id;
+
+  explicit
+  __encoding(const text_encoding& enc, size_t refs = 0)
+  : facet(refs), _M_enc(enc)
+  {
+#if defined _GLIBCXX_HAVE_ICONV
+    if (enc != text_encoding::UTF8 && enc != text_encoding::ASCII)
+      _M_cd = ::iconv_open("UTF-8", enc.name());
+#endif
+  }
+
+  ~__encoding()
+  {
+#if defined _GLIBCXX_HAVE_ICONV
+    if (_M_has_desc())
+      ::iconv_close(_M_cd);
+#endif
+  }
+
+  bool _M_has_desc() const
+  {
+#if defined _GLIBCXX_HAVE_ICONV
+    return _M_cd != (::iconv_t)-1;
+#else
+    return false;
+#endif
+  }
+
+  text_encoding _M_enc;
+#if defined _GLIBCXX_HAVE_ICONV
+  ::iconv_t _M_cd = (::iconv_t)-1;
+#endif
+};
+
+locale::id __encoding::id;
+
+} // namespace
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
@@ -87,8 +140,100 @@ std::text_encoding::_M_is_environment() const
 std::text_encoding
 std::locale::encoding() const
 {
-  return std::__locale_encoding(name().c_str());
+  if (auto enc_facet = std::__try_use_facet<__encoding>(*this))
+    return enc_facet->_M_enc;
+  string name = this->name();
+  if (name == "*")
+    return {};
+  if (name == "C")
+    return text_encoding(text_encoding::ASCII);
+  return __locale_encoding(name.c_str());
 }
 #endif // CHAR_BIT == 8
-
 #endif // _GLIBCXX_USE_NL_LANGINFO_L
+
+namespace std
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace __format
+{
+// Helpers for P2419R2
+// (Clarify handling of encodings in localized formatting of chrono types)
+// Convert a string from the locale's charset to UTF-8.
+
+std::locale
+__with_encoding_conversion(const std::locale& loc)
+{
+#if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
+  const text_encoding locenc = loc.encoding();
+
+  if (locenc == text_encoding::UTF8 || locenc == text_encoding::ASCII
+     || locenc == text_encoding::unknown)
+    return loc;
+
+  auto impl = std::make_unique<locale::_Impl>(*loc._M_impl, 1);
+  auto facetp = std::make_unique<__encoding>(locenc);
+  locale loc2(loc, facetp.get()); // FIXME: PR libstdc++/113704
+  facetp.release();
+  // FIXME: Ideally we wouldn't need to reallocate this string again,
+  // just don't delete[] it in the locale(locale, Facet*) constructor.
+  if (const char* name = loc._M_impl->_M_names[0])
+    {
+      loc2._M_impl->_M_names[0] = new char[strlen(name) + 1];
+      strcpy(loc2._M_impl->_M_names[0], name);
+    }
+  return loc2;
+#else
+  return loc;
+#endif
+}
+
+string_view
+__locale_encoding_to_utf8(const std::locale& loc, string_view str,
+			  string& outbuf)
+{
+#ifdef _GLIBCXX_HAVE_ICONV
+  // Don't need to use __try_use_facet with its dynamic_cast<__encoding*>,
+  // since we know there are no types derived from __encoding. If the array
+  // element is non-null, we have the facet.
+  auto id = __encoding::id._M_id();
+  auto enc_facet = static_cast<const __encoding*>(loc._M_impl->_M_facets[id]);
+  if (!enc_facet || !enc_facet->_M_has_desc())
+    return str;
+
+  size_t inbytesleft = str.size();
+  size_t written = 0;
+  bool done = false;
+
+  auto overwrite = [&](char* p, size_t n) {
+    auto inbytes = const_cast<char*>(str.data()) + str.size() - inbytesleft;
+    char* outbytes = p + written;
+    size_t outbytesleft = n - written;
+    size_t res = ::iconv(enc_facet->_M_cd, &inbytes, &inbytesleft,
+			 &outbytes, &outbytesleft);
+    if (res == (size_t)-1)
+      {
+	if (errno != E2BIG)
+	  {
+	    done = true;
+	    return 0zu;
+	  }
+      }
+    else
+      done = true;
+    written = outbytes - p;
+    return written;
+  };
+  do
+    outbuf.resize_and_overwrite(outbuf.capacity() + (inbytesleft * 3 / 2),
+				overwrite);
+  while (!done);
+  if (outbuf.size())
+    str = outbuf;
+#endif // HAVE_ICONV
+
+  return str;
+}
+} // namespace __format
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
diff --git a/libstdc++-v3/testsuite/20_util/duration/io.cc b/libstdc++-v3/testsuite/20_util/duration/io.cc
index e141baf42dc..30469fb861d 100644
--- a/libstdc++-v3/testsuite/20_util/duration/io.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/clock/file/io.cc b/libstdc++-v3/testsuite/std/time/clock/file/io.cc
index 9ab9f10ec77..2ab4a43c7e3 100644
--- a/libstdc++-v3/testsuite/std/time/clock/file/io.cc
+++ b/libstdc++-v3/testsuite/std/time/clock/file/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/clock/gps/io.cc b/libstdc++-v3/testsuite/std/time/clock/gps/io.cc
index d5405f61520..c3db63ab524 100644
--- a/libstdc++-v3/testsuite/std/time/clock/gps/io.cc
+++ b/libstdc++-v3/testsuite/std/time/clock/gps/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/clock/local/io.cc b/libstdc++-v3/testsuite/std/time/clock/local/io.cc
index bb682cd40cf..bb0ba0df419 100644
--- a/libstdc++-v3/testsuite/std/time/clock/local/io.cc
+++ b/libstdc++-v3/testsuite/std/time/clock/local/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/clock/system/io.cc b/libstdc++-v3/testsuite/std/time/clock/system/io.cc
index 2cc116156f2..dcb28dd51cf 100644
--- a/libstdc++-v3/testsuite/std/time/clock/system/io.cc
+++ b/libstdc++-v3/testsuite/std/time/clock/system/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/clock/tai/io.cc b/libstdc++-v3/testsuite/std/time/clock/tai/io.cc
index 0fd61c0e612..b85fb761d99 100644
--- a/libstdc++-v3/testsuite/std/time/clock/tai/io.cc
+++ b/libstdc++-v3/testsuite/std/time/clock/tai/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/clock/utc/io.cc b/libstdc++-v3/testsuite/std/time/clock/utc/io.cc
index 55c53dc4057..867c912cfdd 100644
--- a/libstdc++-v3/testsuite/std/time/clock/utc/io.cc
+++ b/libstdc++-v3/testsuite/std/time/clock/utc/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/day/io.cc b/libstdc++-v3/testsuite/std/time/day/io.cc
index 36ce7ec7d17..eb9be402e6f 100644
--- a/libstdc++-v3/testsuite/std/time/day/io.cc
+++ b/libstdc++-v3/testsuite/std/time/day/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/exceptions.cc b/libstdc++-v3/testsuite/std/time/exceptions.cc
index 06b8a53c353..1ecf502b62d 100644
--- a/libstdc++-v3/testsuite/std/time/exceptions.cc
+++ b/libstdc++-v3/testsuite/std/time/exceptions.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-effective-target tzdb }
 
diff --git a/libstdc++-v3/testsuite/std/time/format.cc b/libstdc++-v3/testsuite/std/time/format.cc
index d6e35832cb5..18d2171c117 100644
--- a/libstdc++-v3/testsuite/std/time/format.cc
+++ b/libstdc++-v3/testsuite/std/time/format.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/format_localized.cc b/libstdc++-v3/testsuite/std/time/format_localized.cc
new file mode 100644
index 00000000000..f1bfe94fddc
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format_localized.cc
@@ -0,0 +1,48 @@
+// { dg-options "-fexec-charset=UTF-8 -lstdc++exp" }
+// { dg-do run { target c++23 } }
+// { dg-require-namedlocale "ru_UA.koi8u" }
+// { dg-require-namedlocale "es_ES.ISO8859-1" }
+// { dg-require-namedlocale "fr_FR.ISO8859-1" }
+// { dg-require-effective-target cxx11_abi }
+
+// P2419R2
+// Clarify handling of encodings in localized formatting of chrono types
+
+// Localized date-time strings such as "février" should be converted to UTF-8
+// if the locale uses a different encoding.
+
+#include <chrono>
+#include <format>
+#include <testsuite_hooks.h>
+
+void
+test_ru()
+{
+  std::locale loc("ru_UA.koi8u");
+  auto s = std::format(loc, "День недели: {:L}", std::chrono::Monday);
+  VERIFY( s == "День недели: Пн" );
+}
+
+void
+test_es()
+{
+  std::locale loc(ISO_8859(1,es_ES));
+  auto s = std::format(loc, "Día de la semana: {:L%A %a}", std::chrono::Wednesday);
+  VERIFY( s == "Día de la semana: miércoles mié" );
+}
+
+void
+test_fr()
+{
+  std::locale loc(ISO_8859(1,fr_FR));
+  auto s = std::format(loc, "Six mois après {0:L%b}, c'est {1:L%B}.",
+		       std::chrono::February, std::chrono::August);
+  VERIFY( s == "Six mois après févr., c'est août." );
+}
+
+int main()
+{
+  test_ru();
+  test_es();
+  test_fr();
+}
diff --git a/libstdc++-v3/testsuite/std/time/hh_mm_ss/io.cc b/libstdc++-v3/testsuite/std/time/hh_mm_ss/io.cc
index d651dfbcdc8..551e4ed9a37 100644
--- a/libstdc++-v3/testsuite/std/time/hh_mm_ss/io.cc
+++ b/libstdc++-v3/testsuite/std/time/hh_mm_ss/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-timeout-factor 2 }
 
diff --git a/libstdc++-v3/testsuite/std/time/month/io.cc b/libstdc++-v3/testsuite/std/time/month/io.cc
index 99ec0737305..564eed54706 100644
--- a/libstdc++-v3/testsuite/std/time/month/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/month_day/io.cc b/libstdc++-v3/testsuite/std/time/month_day/io.cc
index 30aa5881356..7f34f027ba9 100644
--- a/libstdc++-v3/testsuite/std/time/month_day/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_day/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/month_day_last/io.cc b/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
index c12cee848ed..94d54b9b124 100644
--- a/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_day_last/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/month_weekday/io.cc b/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
index 82cac648905..0fee88bb3a3 100644
--- a/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_weekday/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
index 47968d0e06d..e6a6751bb4a 100644
--- a/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month_weekday_last/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/time_zone/get_info_local.cc b/libstdc++-v3/testsuite/std/time/time_zone/get_info_local.cc
index d2972aca7df..af830374700 100644
--- a/libstdc++-v3/testsuite/std/time/time_zone/get_info_local.cc
+++ b/libstdc++-v3/testsuite/std/time/time_zone/get_info_local.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-effective-target tzdb }
 
diff --git a/libstdc++-v3/testsuite/std/time/weekday/io.cc b/libstdc++-v3/testsuite/std/time/weekday/io.cc
index a56cdaef88c..f102c9250e9 100644
--- a/libstdc++-v3/testsuite/std/time/weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc b/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
index 29255ad5c06..42fc9b914a1 100644
--- a/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday_indexed/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
index 6f76922195d..d069d857ff0 100644
--- a/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday_last/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/year/io.cc b/libstdc++-v3/testsuite/std/time/year/io.cc
index bcaa57faeb7..1bdc95ddbd1 100644
--- a/libstdc++-v3/testsuite/std/time/year/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/year_month/io.cc b/libstdc++-v3/testsuite/std/time/year_month/io.cc
index 7bb3442e299..e7963d31ae6 100644
--- a/libstdc++-v3/testsuite/std/time/year_month/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/year_month_day/io.cc b/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
index cb82ef3b612..e7dc60b9dea 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc b/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
index 3241536a2e6..a57e56a1805 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_day_last/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc b/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
index 65baf1d37ae..e9a5bee7666 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_weekday/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc b/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
index 17f2244420d..fc2328ac001 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_weekday_last/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-namedlocale "fr_FR.ISO8859-15" }
 // { dg-timeout-factor 2 }
diff --git a/libstdc++-v3/testsuite/std/time/zoned_time/1.cc b/libstdc++-v3/testsuite/std/time/zoned_time/1.cc
index 1623aca1c7a..e773f50ae73 100644
--- a/libstdc++-v3/testsuite/std/time/zoned_time/1.cc
+++ b/libstdc++-v3/testsuite/std/time/zoned_time/1.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-effective-target tzdb }
 // { dg-require-effective-target cxx11_abi }
diff --git a/libstdc++-v3/testsuite/std/time/zoned_time/io.cc b/libstdc++-v3/testsuite/std/time/zoned_time/io.cc
index 376b2734f19..c19e2a3c882 100644
--- a/libstdc++-v3/testsuite/std/time/zoned_time/io.cc
+++ b/libstdc++-v3/testsuite/std/time/zoned_time/io.cc
@@ -1,3 +1,4 @@
+// { dg-options "-lstdc++exp" { target c++23 } }
 // { dg-do run { target c++20 } }
 // { dg-require-effective-target cxx11_abi }
 // { dg-timeout-factor 2 }
