diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 5003aa0d97c1c..43e90f06ed504 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -498,6 +498,7 @@ Conversion - Bug in :func:`Series.fillna` returns frame when ``inplace=True`` and ``value`` is dict (:issue:`16156`) - Bug in :attr:`Timestamp.weekday_name` returning a UTC-based weekday name when localized to a timezone (:issue:`17354`) - Bug in ``Timestamp.replace`` when replacing ``tzinfo`` around DST changes (:issue:`15683`) +- Bug in ``Timedelta`` construction and arithmetic that would not propagate the ``Overflow`` exception (:issue:`17367`) Indexing ^^^^^^^^ diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index 6ba37062ac869..077603af96947 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -3514,7 +3514,7 @@ cpdef convert_to_timedelta64(object ts, object unit): ts = np.timedelta64(_delta_to_nanoseconds(ts), 'ns') if isinstance(ts, timedelta): - ts = np.timedelta64(ts) + ts = np.timedelta64(_delta_to_nanoseconds(ts), 'ns') elif not isinstance(ts, np.timedelta64): raise ValueError("Invalid type for timedelta " "scalar: %s" % type(ts)) @@ -3891,8 +3891,7 @@ for _maybe_method_name in dir(NaTType): #---------------------------------------------------------------------- # Conversion routines - -cpdef int64_t _delta_to_nanoseconds(delta): +cpdef int64_t _delta_to_nanoseconds(delta) except? -1: if isinstance(delta, np.ndarray): return delta.astype('m8[ns]').astype('int64') if hasattr(delta, 'nanos'): @@ -3903,6 +3902,7 @@ cpdef int64_t _delta_to_nanoseconds(delta): return delta.astype("timedelta64[ns]").item() if is_integer_object(delta): return delta + return (delta.days * 24 * 60 * 60 * 1000000 + delta.seconds * 1000000 + delta.microseconds) * 1000 diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py index be27334384f6b..e0ccedb834adf 100644 --- a/pandas/tests/indexes/datetimes/test_tools.py +++ b/pandas/tests/indexes/datetimes/test_tools.py @@ -787,6 +787,13 @@ def test_to_datetime_freq(self): assert xp.freq == rs.freq assert xp.tzinfo == rs.tzinfo + def test_to_datetime_overflow(self): + # gh-17637 + # we are overflowing Timedelta range here + + with pytest.raises(OverflowError): + date_range(start='1/1/1700', freq='B', periods=100000) + def test_string_na_nat_conversion(self): # GH #999, #858 diff --git a/pandas/tests/scalar/test_timedelta.py b/pandas/tests/scalar/test_timedelta.py index bc9a0388df9d9..2cabbfacf6416 100644 --- a/pandas/tests/scalar/test_timedelta.py +++ b/pandas/tests/scalar/test_timedelta.py @@ -166,6 +166,13 @@ def test_overflow_on_construction(self): value = pd.Timedelta('1day').value * 20169940 pytest.raises(OverflowError, pd.Timedelta, value) + # xref gh-17637 + with pytest.raises(OverflowError): + pd.Timedelta(7 * 19999, unit='D') + + with pytest.raises(OverflowError): + pd.Timedelta(timedelta(days=13 * 19999)) + def test_total_seconds_scalar(self): # see gh-10939 rng = Timedelta('1 days, 10:11:12.100123456') @@ -612,6 +619,14 @@ def test_timedelta_arithmetic(self): tm.assert_series_equal(result_operator, expected) tm.assert_series_equal(result_method, expected) + def test_arithmetic_overflow(self): + + with pytest.raises(OverflowError): + pd.Timestamp('1700-01-01') + pd.Timedelta(13 * 19999, unit='D') + + with pytest.raises(OverflowError): + pd.Timestamp('1700-01-01') + timedelta(days=13 * 19999) + def test_apply_to_timedelta(self): timedelta_NaT = pd.to_timedelta('NaT')