From 689620ad9ce223836e34aed0df1d48956d1d71e9 Mon Sep 17 00:00:00 2001 From: Harald Husum Date: Fri, 7 Jul 2023 21:01:04 +0200 Subject: [PATCH] BUG: Fix failing hash funciton for certain non-ns resolution `Timedelta`s (#54037) * Add reproducing test * Attempt fix * Add GH reference * Add whatsnew entry * Pre-commit after the fact --- doc/source/whatsnew/v2.1.0.rst | 1 + pandas/_libs/tslibs/timedeltas.pyx | 2 +- pandas/tests/scalar/timedelta/test_timedelta.py | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index eb49c69ad7567..c3f6dcbce2a64 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -393,6 +393,7 @@ Timedelta - :meth:`TimedeltaIndex.map` with ``na_action="ignore"`` now works as expected (:issue:`51644`) - Bug in :class:`TimedeltaIndex` division or multiplication leading to ``.freq`` of "0 Days" instead of ``None`` (:issue:`51575`) - Bug in :class:`Timedelta` with Numpy timedelta64 objects not properly raising ``ValueError`` (:issue:`52806`) +- Bug in :meth:`Timedelta.__hash__`, raising an ``OutOfBoundsTimedelta`` on certain large values of second resolution (:issue:`54037`) - Bug in :meth:`Timedelta.round` with values close to the implementation bounds returning incorrect results instead of raising ``OutOfBoundsTimedelta`` (:issue:`51494`) - Bug in :meth:`arrays.TimedeltaArray.map` and :meth:`TimedeltaIndex.map`, where the supplied callable operated array-wise instead of element-wise (:issue:`51977`) - diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 0981c966c4cd4..28aeb854638b6 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1156,7 +1156,7 @@ cdef class _Timedelta(timedelta): # resolution. try: obj = (<_Timedelta>self)._as_creso((self._creso + 1)) - except OverflowError: + except OutOfBoundsTimedelta: # Doesn't fit, so we're off the hook return hash(self._value) else: diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index 722a68a1dce71..a83c6a8596575 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -305,6 +305,12 @@ def test_resolution(self, td): assert result == expected assert result._creso == expected._creso + def test_hash(self) -> None: + # GH#54037 + second_resolution_max = Timedelta(0).as_unit("s").max + + assert hash(second_resolution_max) + def test_timedelta_class_min_max_resolution(): # when accessed on the class (as opposed to an instance), we default