diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 3e22084d98234..21e45294c87a3 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -582,6 +582,7 @@ Datetimelike - Bug in :class:`DataFrame` comparisons against ``Timestamp``-like objects failing to raise ``TypeError`` for inequality checks with mismatched types (:issue:`8932`,:issue:`22163`) - Bug in :class:`DataFrame` with mixed dtypes including ``datetime64[ns]`` incorrectly raising ``TypeError`` on equality comparisons (:issue:`13128`,:issue:`22163`) - Bug in :meth:`DataFrame.eq` comparison against ``NaT`` incorrectly returning ``True`` or ``NaN`` (:issue:`15697`,:issue:`22163`) +- Bug in :class:`DatetimeIndex` subtraction that incorrectly failed to raise `OverflowError` (:issue:`22492`, :issue:`22508`) Timedelta ^^^^^^^^^ diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 1dd34cdf73ab5..484eb430c82b1 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -459,7 +459,8 @@ def _sub_datelike_dti(self, other): self_i8 = self.asi8 other_i8 = other.asi8 - new_values = self_i8 - other_i8 + new_values = checked_add_with_arr(self_i8, -other_i8, + arr_mask=self._isnan) if self.hasnans or other.hasnans: mask = (self._isnan) | (other._isnan) new_values[mask] = iNaT diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index 879a4e1b4af1a..d597ea834f097 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -1570,6 +1570,40 @@ def test_datetimeindex_sub_timestamp_overflow(self): with pytest.raises(OverflowError): dtimin - variant + def test_datetimeindex_sub_datetimeindex_overflow(self): + # GH#22492, GH#22508 + dtimax = pd.to_datetime(['now', pd.Timestamp.max]) + dtimin = pd.to_datetime(['now', pd.Timestamp.min]) + + ts_neg = pd.to_datetime(['1950-01-01', '1950-01-01']) + ts_pos = pd.to_datetime(['1980-01-01', '1980-01-01']) + + # General tests + expected = pd.Timestamp.max.value - ts_pos[1].value + result = dtimax - ts_pos + assert result[1].value == expected + + expected = pd.Timestamp.min.value - ts_neg[1].value + result = dtimin - ts_neg + assert result[1].value == expected + + with pytest.raises(OverflowError): + dtimax - ts_neg + + with pytest.raises(OverflowError): + dtimin - ts_pos + + # Edge cases + tmin = pd.to_datetime([pd.Timestamp.min]) + t1 = tmin + pd.Timedelta.max + pd.Timedelta('1us') + with pytest.raises(OverflowError): + t1 - tmin + + tmax = pd.to_datetime([pd.Timestamp.max]) + t2 = tmax + pd.Timedelta.min - pd.Timedelta('1us') + with pytest.raises(OverflowError): + tmax - t2 + @pytest.mark.parametrize('names', [('foo', None, None), ('baz', 'bar', None), ('bar', 'bar', 'bar')])