Skip to content

Conversation

@rsaddatimov
Copy link

@rsaddatimov rsaddatimov commented Oct 26, 2025

Closes #105358

@rsaddatimov rsaddatimov requested a review from a team as a code owner October 26, 2025 05:34
@github-actions
Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Oct 26, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 26, 2025

@llvm/pr-subscribers-libcxx

Author: Rafail Shakhin ogly (rsaddatimov)

Changes

Patch is 20.57 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/165132.diff

18 Files Affected:

  • (modified) libcxx/docs/FeatureTestMacroTable.rst (+1-1)
  • (modified) libcxx/docs/ReleaseNotes/22.rst (+1)
  • (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1)
  • (modified) libcxx/include/__chrono/day.h (+8)
  • (modified) libcxx/include/__chrono/duration.h (+13)
  • (modified) libcxx/include/__chrono/leap_second.h (+8)
  • (modified) libcxx/include/__chrono/month.h (+8)
  • (modified) libcxx/include/__chrono/month_weekday.h (+15)
  • (modified) libcxx/include/__chrono/monthday.h (+15)
  • (modified) libcxx/include/__chrono/time_point.h (+14)
  • (modified) libcxx/include/__chrono/weekday.h (+22)
  • (modified) libcxx/include/__chrono/year.h (+8)
  • (modified) libcxx/include/__chrono/year_month.h (+8)
  • (modified) libcxx/include/__chrono/year_month_day.h (+15)
  • (modified) libcxx/include/__chrono/year_month_weekday.h (+17)
  • (modified) libcxx/include/__chrono/zoned_time.h (+10)
  • (modified) libcxx/include/version (+2-2)
  • (added) libcxx/test/std/time/time.hash/time.hash_enabled.pass.cpp (+55)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 8fba6db871f08..a878c46d35cbe 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -88,7 +88,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_byte``                                         ``201603L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_chrono``                                       ``201611L``
+    ``__cpp_lib_chrono``                                       ``202510L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_clamp``                                        ``201603L``
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 25d33a9c2eb50..7ea3529642c90 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -38,6 +38,7 @@ What's New in Libc++ 22.0.0?
 Implemented Papers
 ------------------
 
+- P2592R3: Hashing support for ``std::chrono`` value classes (`Github <https://llvm.org/PR105358>`__)
 - P2321R2: ``zip`` (`Github <https://llvm.org/PR105169>`__) (The paper is partially implemented. ``zip_transform_view``
   is implemented in this release)
 - P3044R2: sub-``string_view`` from ``string`` (`Github <https://llvm.org/PR148140>`__)
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index a5423acf0d419..493e6a3c9ed44 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -1,6 +1,6 @@
 "Paper #","Paper Name","Meeting","Status","First released version","GitHub issue","Notes"
 "`P2497R0 <https://wg21.link/P2497R0>`__","Testing for success or failure of ``<charconv>`` functions","2023-06 (Varna)","|Complete|","18","`#105357 <https://github.com/llvm/llvm-project/issues/105357>`__",""
-"`P2592R3 <https://wg21.link/P2592R3>`__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","","`#105358 <https://github.com/llvm/llvm-project/issues/105358>`__",""
+"`P2592R3 <https://wg21.link/P2592R3>`__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","|Complete|","22","`#105358 <https://github.com/llvm/llvm-project/issues/105358>`__",""
 "`P2587R3 <https://wg21.link/P2587R3>`__","``to_string`` or not ``to_string``","2023-06 (Varna)","","","`#105359 <https://github.com/llvm/llvm-project/issues/105359>`__",""
 "`P2562R1 <https://wg21.link/P2562R1>`__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Complete|","21","`#105360 <https://github.com/llvm/llvm-project/issues/105360>`__",""
 "`P2545R4 <https://wg21.link/P2545R4>`__","Read-Copy Update (RCU)","2023-06 (Varna)","","","`#105361 <https://github.com/llvm/llvm-project/issues/105361>`__",""
diff --git a/libcxx/include/__chrono/day.h b/libcxx/include/__chrono/day.h
index f5b14689a78ac..5c39bf16f72ea 100644
--- a/libcxx/include/__chrono/day.h
+++ b/libcxx/include/__chrono/day.h
@@ -13,6 +13,7 @@
 #include <__chrono/duration.h>
 #include <__compare/ordering.h>
 #include <__config>
+#include <__functional/hash.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -92,6 +93,13 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr day& day::operator-=(const days& __dd) no
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::day> : public __unary_function<chrono::day, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::day& __d) const _NOEXCEPT {
+    return hash<unsigned>{}(static_cast<unsigned>(__d));
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/duration.h b/libcxx/include/__chrono/duration.h
index 57fa64d650068..3e04891f5b0c6 100644
--- a/libcxx/include/__chrono/duration.h
+++ b/libcxx/include/__chrono/duration.h
@@ -13,6 +13,7 @@
 #include <__compare/ordering.h>
 #include <__compare/three_way_comparable.h>
 #include <__config>
+#include <__functional/hash.h>
 #include <__type_traits/common_type.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/is_convertible.h>
@@ -538,6 +539,18 @@ using namespace literals::chrono_literals;
 
 #endif // _LIBCPP_STD_VER >= 14
 
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Rep, class _Period>
+  requires __has_enabled_hash<_Rep>::value
+struct hash<chrono::duration<_Rep, _Period>> : public __unary_function<chrono::duration<_Rep, _Period>, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::duration<_Rep, _Period>& __d) const {
+    return hash<_Rep>{}(__d.count());
+  }
+};
+
+#endif // _LIBCPP_STD_VER >= 20
+
 _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
diff --git a/libcxx/include/__chrono/leap_second.h b/libcxx/include/__chrono/leap_second.h
index 1857bef80376e..cf7a2c16626d0 100644
--- a/libcxx/include/__chrono/leap_second.h
+++ b/libcxx/include/__chrono/leap_second.h
@@ -22,6 +22,7 @@
 #  include <__compare/ordering.h>
 #  include <__compare/three_way_comparable.h>
 #  include <__config>
+#  include <__functional/hash.h>
 #  include <__utility/private_constructor_tag.h>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -122,6 +123,13 @@ class leap_second {
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::leap_second> : public __unary_function<chrono::leap_second, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::leap_second& __lp) const _NOEXCEPT {
+    return hash<chrono::seconds>{}(__lp.value());
+  }
+};
+
 #  endif // _LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__chrono/month.h b/libcxx/include/__chrono/month.h
index 77c67d0954efa..d76efd4973193 100644
--- a/libcxx/include/__chrono/month.h
+++ b/libcxx/include/__chrono/month.h
@@ -13,6 +13,7 @@
 #include <__chrono/duration.h>
 #include <__compare/ordering.h>
 #include <__config>
+#include <__functional/hash.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -108,6 +109,13 @@ inline constexpr month December{12};
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::month> : public __unary_function<chrono::month, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::month& __m) const _NOEXCEPT {
+    return hash<unsigned>{}(static_cast<unsigned>(__m));
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/month_weekday.h b/libcxx/include/__chrono/month_weekday.h
index 7919879655214..a46526eca2853 100644
--- a/libcxx/include/__chrono/month_weekday.h
+++ b/libcxx/include/__chrono/month_weekday.h
@@ -13,6 +13,7 @@
 #include <__chrono/month.h>
 #include <__chrono/weekday.h>
 #include <__config>
+#include <__functional/hash.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -98,6 +99,20 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday_last operator/(const weekda
 }
 } // namespace chrono
 
+template <>
+struct hash<chrono::month_weekday> : public __unary_function<chrono::month_weekday, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::month_weekday& __mw) const _NOEXCEPT {
+    return hash<chrono::month>{}(__mw.month()) ^ hash<chrono::weekday_indexed>{}(__mw.weekday_indexed());
+  }
+};
+
+template <>
+struct hash<chrono::month_weekday_last> : public __unary_function<chrono::month_weekday_last, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::month_weekday_last& __mwl) const _NOEXCEPT {
+    return hash<chrono::month>{}(__mwl.month()) ^ hash<chrono::weekday_last>{}(__mwl.weekday_last());
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/monthday.h b/libcxx/include/__chrono/monthday.h
index 57712cf0b65a8..79c2a4c9f0a42 100644
--- a/libcxx/include/__chrono/monthday.h
+++ b/libcxx/include/__chrono/monthday.h
@@ -15,6 +15,7 @@
 #include <__chrono/month.h>
 #include <__compare/ordering.h>
 #include <__config>
+#include <__functional/hash.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -126,6 +127,20 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr month_day_last operator/(last_spec, int _
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::month_day> : public __unary_function<chrono::month_day, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::month_day& __md) const _NOEXCEPT {
+    return hash<chrono::month>{}(__md.month()) ^ hash<chrono::day>{}(__md.day());
+  }
+};
+
+template <>
+struct hash<chrono::month_day_last> : public __unary_function<chrono::month_day_last, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::month_day_last& __mdl) const _NOEXCEPT {
+    return hash<chrono::month>{}(__mdl.month());
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/time_point.h b/libcxx/include/__chrono/time_point.h
index bc2c7798a630b..02720ec66228e 100644
--- a/libcxx/include/__chrono/time_point.h
+++ b/libcxx/include/__chrono/time_point.h
@@ -14,6 +14,7 @@
 #include <__compare/ordering.h>
 #include <__compare/three_way_comparable.h>
 #include <__config>
+#include <__functional/hash.h>
 #include <__type_traits/common_type.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/is_convertible.h>
@@ -224,6 +225,19 @@ operator-(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
 
 } // namespace chrono
 
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Clock, class _Duration>
+  requires __has_enabled_hash<_Duration>::value
+struct hash<chrono::time_point<_Clock, _Duration>>
+    : public __unary_function<chrono::time_point<_Clock, _Duration>, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::time_point<_Clock, _Duration>& __tp) const {
+    return hash<_Duration>{}(__tp.time_since_epoch());
+  }
+};
+
+#endif // _LIBCPP_STD_VER >= 20
+
 _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
diff --git a/libcxx/include/__chrono/weekday.h b/libcxx/include/__chrono/weekday.h
index 728cbb844633f..2fc988a9f4b57 100644
--- a/libcxx/include/__chrono/weekday.h
+++ b/libcxx/include/__chrono/weekday.h
@@ -15,6 +15,7 @@
 #include <__chrono/system_clock.h>
 #include <__chrono/time_point.h>
 #include <__config>
+#include <__functional/hash.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -160,6 +161,27 @@ inline constexpr weekday Saturday{6};
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::weekday> : public __unary_function<chrono::weekday, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::weekday& __w) const _NOEXCEPT {
+    return hash<unsigned>{}(__w.c_encoding());
+  }
+};
+
+template <>
+struct hash<chrono::weekday_indexed> : public __unary_function<chrono::weekday_indexed, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::weekday_indexed& __wi) const _NOEXCEPT {
+    return hash<chrono::weekday>{}(__wi.weekday()) ^ hash<unsigned>{}(__wi.index());
+  }
+};
+
+template <>
+struct hash<chrono::weekday_last> : public __unary_function<chrono::weekday_last, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::weekday_last& __wl) const _NOEXCEPT {
+    return hash<chrono::weekday>{}(__wl.weekday());
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/year.h b/libcxx/include/__chrono/year.h
index 2ae5180cb8fc9..4ee4186dcf533 100644
--- a/libcxx/include/__chrono/year.h
+++ b/libcxx/include/__chrono/year.h
@@ -13,6 +13,7 @@
 #include <__chrono/duration.h>
 #include <__compare/ordering.h>
 #include <__config>
+#include <__functional/hash.h>
 #include <limits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -109,6 +110,13 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool year::ok() const noexcept {
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::year> : public __unary_function<chrono::year, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::year& __y) const _NOEXCEPT {
+    return hash<int>{}(static_cast<int>(__y));
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/year_month.h b/libcxx/include/__chrono/year_month.h
index cf9234bdb4625..a3e1429527bea 100644
--- a/libcxx/include/__chrono/year_month.h
+++ b/libcxx/include/__chrono/year_month.h
@@ -15,6 +15,7 @@
 #include <__chrono/year.h>
 #include <__compare/ordering.h>
 #include <__config>
+#include <__functional/hash.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -116,6 +117,13 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator-=(const
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::year_month> : public __unary_function<chrono::year_month, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::year_month& __ym) const _NOEXCEPT {
+    return hash<chrono::year>{}(__ym.year()) ^ hash<chrono::month>{}(__ym.month());
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/year_month_day.h b/libcxx/include/__chrono/year_month_day.h
index a0510a14f4ede..b0c05716bdba3 100644
--- a/libcxx/include/__chrono/year_month_day.h
+++ b/libcxx/include/__chrono/year_month_day.h
@@ -21,6 +21,7 @@
 #include <__chrono/year_month.h>
 #include <__compare/ordering.h>
 #include <__config>
+#include <__functional/hash.h>
 #include <limits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -330,6 +331,20 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool year_month_day::ok() const noexcept
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::year_month_day> : public __unary_function<chrono::year_month_day, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::year_month_day& __ymd) const _NOEXCEPT {
+    return hash<chrono::year>{}(__ymd.year()) ^ hash<chrono::month>{}(__ymd.month()) ^ hash<chrono::day>{}(__ymd.day());
+  }
+};
+
+template <>
+struct hash<chrono::year_month_day_last> : public __unary_function<chrono::year_month_day_last, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::year_month_day_last& __ymdl) const _NOEXCEPT {
+    return hash<chrono::year>{}(__ymdl.year()) ^ hash<chrono::month_day_last>{}(__ymdl.month_day_last());
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/year_month_weekday.h b/libcxx/include/__chrono/year_month_weekday.h
index 0c3dd494c8787..6ae704c397b97 100644
--- a/libcxx/include/__chrono/year_month_weekday.h
+++ b/libcxx/include/__chrono/year_month_weekday.h
@@ -22,6 +22,7 @@
 #include <__chrono/year_month.h>
 #include <__chrono/year_month_day.h>
 #include <__config>
+#include <__functional/hash.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -280,6 +281,22 @@ year_month_weekday_last::operator-=(const years& __dy) noexcept {
 
 } // namespace chrono
 
+template <>
+struct hash<chrono::year_month_weekday> : public __unary_function<chrono::year_month_weekday, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::year_month_weekday& __ymw) const _NOEXCEPT {
+    return hash<chrono::year>{}(__ymw.year()) ^ hash<chrono::month>{}(__ymw.month()) ^
+           hash<chrono::weekday_indexed>{}(__ymw.weekday_indexed());
+  }
+};
+
+template <>
+struct hash<chrono::year_month_weekday_last> : public __unary_function<chrono::year_month_weekday_last, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::year_month_weekday_last& __ymwl) const _NOEXCEPT {
+    return hash<chrono::year>{}(__ymwl.year()) ^ hash<chrono::month>{}(__ymwl.month()) ^
+           hash<chrono::weekday_last>{}(__ymwl.weekday_last());
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__chrono/zoned_time.h b/libcxx/include/__chrono/zoned_time.h
index 8db687a422ab1..5f110d1721502 100644
--- a/libcxx/include/__chrono/zoned_time.h
+++ b/libcxx/include/__chrono/zoned_time.h
@@ -24,6 +24,7 @@
 #  include <__chrono/tzdb_list.h>
 #  include <__concepts/constructible.h>
 #  include <__config>
+#  include <__functional/hash.h>
 #  include <__type_traits/common_type.h>
 #  include <__type_traits/conditional.h>
 #  include <__type_traits/remove_cvref.h>
@@ -216,6 +217,15 @@ operator==(const zoned_time<_Duration1, _TimeZonePtr>& __lhs, const zoned_time<_
 
 } // namespace chrono
 
+template <class _Duration, class _TimeZonePtr>
+  requires __has_enabled_hash<_Duration>::value && __has_enabled_hash<_TimeZonePtr>::value
+struct hash<chrono::zoned_time<_Duration, _TimeZonePtr>>
+    : public __unary_function<chrono::zoned_time<_Duration, _TimeZonePtr>, size_t> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const chrono::zoned_time<_Duration, _TimeZonePtr>& __zt) const {
+    return hash<chrono::sys_time<_Duration>>{}(__zt.get_sys_time()) ^ hash<_TimeZonePtr>{}(__zt.get_time_zone());
+  }
+};
+
 #  endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&
          // _LIBCPP_HAS_LOCALIZATION
 
diff --git a/libcxx/include/version b/libcxx/include/version
index 0fef1bb87cf60..5200d72ed1ea5 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -57,7 +57,7 @@ __cpp_lib_byteswap                                      202110L <bit>
 __cpp_lib_char8_t                                       201907L <atomic> <filesystem> <istream>
                                                                 <limits> <locale> <ostream>
                                                                 <string> <string_view>
-__cpp_lib_chrono                                        201611L <chrono>
+__cpp_lib_chrono                                        202510L <chrono>
 __cpp_lib_chrono_udls                                   201304L <chrono>
 __cpp_lib_clamp                                         201603L <algorithm>
 __cpp_lib_common_reference                              202302L <type_traits>
@@ -332,7 +332,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_bool_constant                        201505L
 # define __cpp_lib_boyer_moore_searcher                 201603L
 # define __cpp_lib_byte                                 201603L
-# define __cpp_lib_chrono                               201611L
+# define __cpp_lib_chrono                               202510L
 # define __cpp_lib_clamp                                201603L
 # define __cpp_lib_enable_shared_from_this              201603L
 // # define __cpp_lib_execution                            201603L
diff --git a/libcxx/test/std/time/time.hash/time.hash_enabled.pass.cpp b/libcxx/test/std/time/time.hash/time.hash_enabled.pass.cpp
new file mode 100644
index 0000000000000..e935a121c0ab0
--- /dev/null
+++ b/libcxx/test/std/time/time.hash/time.hash_enabled.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <chrono>
+
+// Test that <chrono> provides all of the hash specializations.
+
+#include <chrono>
+#include "poisoned_hash_helper.h"
+namespace chrono = std::chrono;
+
+int main(int, char**) {
+  test_hash_enabled<chrono::nanoseconds>();
+  test_hash_enabled<chrono::microseconds>();
+  test_hash_enabled<chrono::milliseconds>();
+  test_hash_enabled<chrono::seconds>();
+  test_hash_enabled<chrono::minutes>();
+  test_hash_enabled<chrono::hours>();
+  test_hash_enabled<chrono::days>();
+  test_hash_enabled<chrono::weeks>();
+  test_hash_enabled<chrono::months>();
+  test_hash_enabled<chrono::years>();
+
+  test_hash_enabled<chrono::day>();
+  test_hash_enabled<chrono::month>();
+  test_hash_enabled<chrono::year>();
+
+  test_hash_enabled<chrono::weekday>();
+  test_hash_enabled<chrono::weekday_indexed>();
+  test_hash_enabled(chrono::weekday_last(chrono::weekday{}));
+
+  test_hash_enabled<chrono::month_day>();
+  test_hash_enabled(chrono::month_day_last(chrono::month{}));
+
+  test_hash_enabled(chro...
[truncated]

@H-G-Hristov
Copy link
Contributor

H-G-Hristov commented Oct 26, 2025

P.S. I updated the description accordingly.


template <>
struct hash<chrono::day> {
_LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::day& __d) noexcept {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test failures indicated that we should include <__cstddef/size_t.h> in every header where hash specialization is being added.

#include <__compare/ordering.h>
#include <__compare/three_way_comparable.h>
#include <__config>
#include <__functional/hash.h>
Copy link
Contributor

@frederick-vs-ja frederick-vs-ja Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thing we can either

  • add <__chrono/duration_hash.h> and <__chrono/time_point_hash.h> (together with changes to CMakeList.txt and module.modulemap.in) and move hash specializations into them, which avoids changing transitive includes; or
  • just modify libcxx/test/libcxx/transitive_includes/cxx26.csv to add entries memory_resource cstring, mutex cstring, and shared_mutex cstring to resolve test failures about transitive includes.

I'm not sure which approach is better. The first one is more complicated but possibly better for compiler throughput.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should go for the second approach. The first one is likely to raise ODR violation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P2592R3: Hashing support for std::chrono value classes

4 participants