From bfb76da0e01679e6e3a5f1577182304fbead0d93 Mon Sep 17 00:00:00 2001 From: Brock Date: Wed, 22 Feb 2023 16:58:33 -0800 Subject: [PATCH 1/2] BUG: TDI divison giving bogus .freq --- doc/source/whatsnew/v2.1.0.rst | 2 +- pandas/core/arrays/timedeltas.py | 18 +++++++----------- .../tests/indexes/timedeltas/test_timedelta.py | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index aeaafbc4c125d..a82ee19607d8d 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -121,7 +121,7 @@ Datetimelike Timedelta ^^^^^^^^^ -- +- Bug in :class:`TimedeltaIndex` division or multiplication leading to ``.freq`` of "0 Days" instead of ``None`` (:issue:`??`) - Timezones diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index e7a0ddba1fccc..7c9bc0a9e9438 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: + # 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..d381dfec520e2 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): + # 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) From 4383e3f230add303db4797c3ab9274ef75a77bc0 Mon Sep 17 00:00:00 2001 From: Brock Date: Wed, 22 Feb 2023 16:59:32 -0800 Subject: [PATCH 2/2] GH ref --- doc/source/whatsnew/v2.1.0.rst | 2 +- pandas/core/arrays/timedeltas.py | 2 +- pandas/tests/indexes/timedeltas/test_timedelta.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index a82ee19607d8d..7c327be6b40b3 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -121,7 +121,7 @@ Datetimelike Timedelta ^^^^^^^^^ -- Bug in :class:`TimedeltaIndex` division or multiplication leading to ``.freq`` of "0 Days" instead of ``None`` (:issue:`??`) +- 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 7c9bc0a9e9438..d38145295a4db 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -468,7 +468,7 @@ def __mul__(self, other) -> TimedeltaArray: if self.freq is not None and not isna(other): freq = self.freq * other if freq.n == 0: - # Better to have no freq than an incorrect one + # GH#51575 Better to have no freq than an incorrect one 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 d381dfec520e2..1170fd6a053d9 100644 --- a/pandas/tests/indexes/timedeltas/test_timedelta.py +++ b/pandas/tests/indexes/timedeltas/test_timedelta.py @@ -159,7 +159,7 @@ def test_freq_conversion(self, index_or_series): tm.assert_equal(result, expected) def test_arithmetic_zero_freq(self): - # don't get a .freq with freq.n = 0 + # 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