diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
index 362bb5aa9e9..a337007266e 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -150,7 +150,9 @@ namespace __detail
       __s.flags(__os.flags());
       __s.imbue(__os.getloc());
       __s.precision(__os.precision());
-      __s << __d.count();
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 4118. How should duration formatters format custom rep types?
+      __s << +__d.count();
       __detail::__fmt_units_suffix<period, _CharT>(_Out(__s));
       __os << std::move(__s).str();
       return __os;
@@ -635,8 +637,10 @@ namespace __format
 		case 'Q':
 		  // %Q The duration's numeric value.
 		  if constexpr (chrono::__is_duration_v<_Tp>)
+		    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+		    // 4118. How should duration formatters format custom rep?
 		    __out = std::format_to(__print_sign(), _S_empty_spec,
-					   __t.count());
+					   +__t.count());
 		  else
 		    __throw_format_error("chrono format error: argument is "
 					 "not a duration");
@@ -1703,6 +1707,7 @@ namespace __format
 /// @endcond
 
   template<typename _Rep, typename _Period, typename _CharT>
+    requires __format::__formattable_impl<_Rep, _CharT>
     struct formatter<chrono::duration<_Rep, _Period>, _CharT>
     {
       constexpr typename basic_format_parse_context<_CharT>::iterator
diff --git a/libstdc++-v3/testsuite/20_util/duration/io.cc b/libstdc++-v3/testsuite/20_util/duration/io.cc
index 57020f4f953..383fb60afe2 100644
--- a/libstdc++-v3/testsuite/20_util/duration/io.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/io.cc
@@ -23,6 +23,24 @@ test01()
   VERIFY( s == "3[2]s" );
   std::getline(ss, s);
   VERIFY( s == "9[2/3]s" );
+
+  // LWG 4118. How should duration formatters format custom rep types?
+  ss.str("");
+  ss << duration<char>(121) << ' ';
+  ss << duration<wchar_t>(122) << ' ';
+  ss << duration<signed char>(123) << ' ';
+  ss << duration<unsigned char>(124) << ' ';
+  ss << duration<char8_t>(125) << ' ';
+  ss << duration<char16_t>(126) << ' ';
+  ss << duration<char32_t>(127) << ' ';
+  VERIFY( ss.str() == "121s 122s 123s 124s 125s 126s 127s " );
+
+  ss.str("");
+  ss << std::hex << std::uppercase << duration<const char>(0x1A) << ' ';
+  ss << std::hex << std::uppercase << duration<const wchar_t>(0x2A) << ' ';
+  ss << std::hex << std::uppercase << duration<signed char>(0x3A) << ' ';
+  ss << std::scientific << duration<const double>(4.5) << ' ';
+  VERIFY( ss.str() == "1As 2As 3As 4.500000E+00s " );
 }
 
 void
@@ -44,6 +62,24 @@ test02()
   VERIFY( s == L"3[2]s" );
   std::getline(ss, s);
   VERIFY( s == L"9[2/3]s" );
+
+  // LWG 4118. How should duration formatters format custom rep types?
+  ss.str(L"");
+  ss << duration<char>(121) << ' ';
+  ss << duration<wchar_t>(122) << ' ';
+  ss << duration<signed char>(123) << ' ';
+  ss << duration<unsigned char>(124) << ' ';
+  ss << duration<char8_t>(125) << ' ';
+  ss << duration<char16_t>(126) << ' ';
+  ss << duration<char32_t>(127) << ' ';
+  VERIFY( ss.str() == L"121s 122s 123s 124s 125s 126s 127s " );
+
+  ss.str(L"");
+  ss << std::hex << std::uppercase << duration<const char>(0x1A) << ' ';
+  ss << std::hex << std::uppercase << duration<const wchar_t>(0x2A) << ' ';
+  ss << std::hex << std::uppercase << duration<signed char>(0x3A) << ' ';
+  ss << std::scientific << duration<const double>(4.5) << ' ';
+  VERIFY( ss.str() == L"1As 2As 3As 4.500000E+00s " );
 #endif
 }
 
@@ -114,6 +150,36 @@ test_format()
   VERIFY( s == expected );
   s = std::format("{:%Q%q}", minsec);
   VERIFY( s == expected );
+
+  // LWG 4118. How should duration formatters format custom rep types?
+  s = std::format("{}", std::chrono::duration<char>(100));
+  VERIFY( s == "100s" );
+  s = std::format("{:%Q}", std::chrono::duration<char>(101));
+  VERIFY( s == "101" );
+#ifdef _GLIBCXX_USE_WCHAR_T
+  ws = std::format(L"{}", std::chrono::duration<char>(102));
+  VERIFY( ws == L"102s" );
+  ws = std::format(L"{}", std::chrono::duration<wchar_t>(103));
+  VERIFY( ws == L"103s" );
+#endif
+  s = std::format("{}", std::chrono::duration<signed char>(50));
+  VERIFY( s == "50s" );
+  s = std::format("{:%Q}", std::chrono::duration<signed char>(51));
+  VERIFY( s == "51" );
+  s = std::format("{}", std::chrono::duration<unsigned char>(52));
+  VERIFY( s == "52s" );
+  s = std::format("{:%Q}", std::chrono::duration<unsigned char>(53));
+  VERIFY( s == "53" );
+
+#if __cplusplus > 202002L
+  static_assert( ! std::formattable<std::chrono::duration<wchar_t>, char> );
+  static_assert( ! std::formattable<std::chrono::duration<char8_t>, char> );
+  static_assert( ! std::formattable<std::chrono::duration<char16_t>, char> );
+  static_assert( ! std::formattable<std::chrono::duration<char32_t>, char> );
+  static_assert( ! std::formattable<std::chrono::duration<char8_t>, wchar_t> );
+  static_assert( ! std::formattable<std::chrono::duration<char16_t>, wchar_t> );
+  static_assert( ! std::formattable<std::chrono::duration<char32_t>, wchar_t> );
+#endif
 }
 
 void
