From fa674e5b94c17077dcc6c904c999b6294b35c69d Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 21 Jun 2026 12:35:48 -0700 Subject: [PATCH] BUG: Series.sum on overflowing timedelta64 raises OutOfBoundsTimedelta (GH-43178) Series.sum on a timedelta64 reduction that overflowed int64 raised a plain ValueError. Raise OutOfBoundsTimedelta (a ValueError subclass) instead, matching the rest of pandas' overflow-on-timedelta behavior. Split out of GH-65515, which also tightens timedelta64 multiplication overflow handling. Co-Authored-By: Claude Opus 4.8 (1M context) --- doc/source/whatsnew/v3.1.0.rst | 1 + pandas/core/nanops.py | 5 +++-- pandas/tests/series/test_reductions.py | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v3.1.0.rst b/doc/source/whatsnew/v3.1.0.rst index 10f24f01e7688..55141875a71a1 100644 --- a/doc/source/whatsnew/v3.1.0.rst +++ b/doc/source/whatsnew/v3.1.0.rst @@ -269,6 +269,7 @@ Timedelta - Bug in :class:`DateOffset` where ``DateOffset(1)`` and ``DateOffset(days=1)`` returned different results near daylight saving time transitions (:issue:`61862`) - Bug in :class:`Timedelta` constructor where keyword arguments (e.g. ``days=365000``) that exceeded nanosecond int64 bounds raised ``OutOfBoundsTimedelta`` instead of falling back to a coarser resolution (:issue:`46587`) - Bug in :func:`to_timedelta` where passing ``np.str_`` objects would fail in Cython string parsing (:issue:`48974`) +- Bug in :meth:`Series.sum` on an overflowing ``timedelta64`` series raising a plain ``ValueError`` instead of :class:`OutOfBoundsTimedelta` (:issue:`43178`) - Bug in ``Series.dt.seconds`` and ``Series.dt.microseconds`` with :class:`ArrowDtype` durations returning the ``Series.dt.components`` field values (e.g. 0-59 for seconds, or 0 for ``microseconds`` on a ``"ms"`` unit) instead of the totals within each day and second respectively, inconsistent with NumPy-backed timedeltas (:issue:`63470`) Timezones diff --git a/pandas/core/nanops.py b/pandas/core/nanops.py index 1794445969c0c..e497a3bab98bb 100644 --- a/pandas/core/nanops.py +++ b/pandas/core/nanops.py @@ -20,6 +20,7 @@ lib, ) import pandas._libs.algos as libalgos +from pandas._libs.tslibs import OutOfBoundsTimedelta from pandas.compat._optional import import_optional_dependency from pandas.core.dtypes.common import ( @@ -375,8 +376,8 @@ def _wrap_results(result, dtype: np.dtype, fill_value=None): result = np.timedelta64("NaT", unit) # type: ignore[call-overload] elif np.fabs(result) > lib.i8max: - # raise if we have a timedelta64[ns] which is too large - raise ValueError("overflow in timedelta operation") + # GH#43178: raise if the result is too large for the dtype's unit + raise OutOfBoundsTimedelta("overflow in timedelta operation") else: # return a timedelta64 with the original unit result = np.int64(result).astype(dtype, copy=False) diff --git a/pandas/tests/series/test_reductions.py b/pandas/tests/series/test_reductions.py index 10f74a3799634..f389e8d2ef820 100644 --- a/pandas/tests/series/test_reductions.py +++ b/pandas/tests/series/test_reductions.py @@ -114,12 +114,13 @@ def test_td64_summation_overflow(): assert np.allclose(result._value / 1000, expected._value / 1000) # sum + # GH#43178: OutOfBoundsTimedelta (a ValueError subclass) is raised msg = "overflow in timedelta operation" - with pytest.raises(ValueError, match=msg): + with pytest.raises(pd.errors.OutOfBoundsTimedelta, match=msg): (ser - ser.min()).sum() s1 = ser[0:10000] - with pytest.raises(ValueError, match=msg): + with pytest.raises(pd.errors.OutOfBoundsTimedelta, match=msg): (s1 - s1.min()).sum() s2 = ser[0:1000] (s2 - s2.min()).sum()