diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 1eab7b2fc411f..ed85b952e3bcd 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -124,6 +124,7 @@ Datetimelike Timedelta ^^^^^^^^^ - Bug in :meth:`Timedelta.round` with values close to the implementation bounds returning incorrect results instead of raising ``OutOfBoundsTimedelta`` (:issue:`51494`) +- Bug in :class:`TimedeltaIndex` division or multiplication leading to ``.freq`` of "0 Days" instead of ``None`` (:issue:`51575`) - Timezones diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index e7a0ddba1fccc..d38145295a4db 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -467,6 +467,9 @@ def __mul__(self, other) -> TimedeltaArray: freq = None if self.freq is not None and not isna(other): freq = self.freq * other + if freq.n == 0: + # GH#51575 Better to have no freq than an incorrect one + freq = None return type(self)._simple_new(result, dtype=result.dtype, freq=freq) if not hasattr(other, "dtype"): @@ -526,17 +529,10 @@ def _scalar_divlike_op(self, other, op): # Note: freq gets division, not floor-division, even if op # is floordiv. freq = self.freq / other - - # TODO: 2022-12-24 test_ufunc_coercions, test_tdi_ops_attributes - # get here for truediv, no tests for floordiv - - if op is operator.floordiv: - if freq.nanos == 0 and self.freq.nanos != 0: - # e.g. if self.freq is Nano(1) then dividing by 2 - # rounds down to zero - # TODO: 2022-12-24 should implement the same check - # for truediv case - freq = None + if freq.nanos == 0 and self.freq.nanos != 0: + # e.g. if self.freq is Nano(1) then dividing by 2 + # rounds down to zero + freq = None return type(self)._simple_new(result, dtype=result.dtype, freq=freq) diff --git a/pandas/tests/indexes/timedeltas/test_timedelta.py b/pandas/tests/indexes/timedeltas/test_timedelta.py index 48dd1fd02d228..1170fd6a053d9 100644 --- a/pandas/tests/indexes/timedeltas/test_timedelta.py +++ b/pandas/tests/indexes/timedeltas/test_timedelta.py @@ -157,3 +157,21 @@ def test_freq_conversion(self, index_or_series): assert expected.dtype == "m8[s]" result = td.astype("timedelta64[s]") tm.assert_equal(result, expected) + + def test_arithmetic_zero_freq(self): + # GH#51575 don't get a .freq with freq.n = 0 + tdi = timedelta_range(0, periods=100, freq="ns") + result = tdi / 2 + assert result.freq is None + expected = tdi[:50].repeat(2) + tm.assert_index_equal(result, expected) + + result2 = tdi // 2 + assert result2.freq is None + expected2 = expected + tm.assert_index_equal(result2, expected2) + + result3 = tdi * 0 + assert result3.freq is None + expected3 = tdi[:1].repeat(100) + tm.assert_index_equal(result3, expected3)