diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 33464a73e7821..27f864842205d 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -980,6 +980,7 @@ Datetimelike - Bug in :meth:`DataFrame.fillna` raising an ``AssertionError`` instead of ``OutOfBoundsDatetime`` when filling a ``datetime64[ns]`` column with an out-of-bounds timestamp. Now correctly raises ``OutOfBoundsDatetime``. (:issue:`61208`) - Bug in :meth:`DataFrame.min` and :meth:`DataFrame.max` casting ``datetime64`` and ``timedelta64`` columns to ``float64`` and losing precision (:issue:`60850`) - Bug in :meth:`Dataframe.agg` with df with missing values resulting in IndexError (:issue:`58810`) +- Bug in :meth:`DateOffset.rollback` (and subclass methods) with ``normalize=True`` rolling back one offset too long (:issue:`32616`) - Bug in :meth:`DatetimeIndex.is_year_start` and :meth:`DatetimeIndex.is_quarter_start` does not raise on Custom business days frequencies bigger then "1C" (:issue:`58664`) - Bug in :meth:`DatetimeIndex.is_year_start` and :meth:`DatetimeIndex.is_quarter_start` returning ``False`` on double-digit frequencies (:issue:`58523`) - Bug in :meth:`DatetimeIndex.union` and :meth:`DatetimeIndex.intersection` when ``unit`` was non-nanosecond (:issue:`59036`) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index ad3fb72d31559..8fb5e739d3a4e 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -692,6 +692,9 @@ cdef class BaseOffset: Rolled timestamp if not on offset, otherwise unchanged timestamp. """ dt = Timestamp(dt) + if self.normalize and (dt - dt.normalize())._value != 0: + # GH#32616 + dt = dt.normalize() if not self.is_on_offset(dt): dt = dt - type(self)(1, normalize=self.normalize, **self.kwds) return dt diff --git a/pandas/tests/tseries/offsets/test_offsets.py b/pandas/tests/tseries/offsets/test_offsets.py index 28badd877fccb..3666342aef433 100644 --- a/pandas/tests/tseries/offsets/test_offsets.py +++ b/pandas/tests/tseries/offsets/test_offsets.py @@ -431,22 +431,6 @@ def test_rollback(self, offset_types): for k in norm_expected: norm_expected[k] = Timestamp(norm_expected[k].date()) - normalized = { - "Day": Timestamp("2010-12-31 00:00:00"), - "DateOffset": Timestamp("2010-12-31 00:00:00"), - "MonthBegin": Timestamp("2010-12-01 00:00:00"), - "SemiMonthBegin": Timestamp("2010-12-15 00:00:00"), - "YearBegin": Timestamp("2010-01-01 00:00:00"), - "HalfYearBegin": Timestamp("2010-07-01 00:00:00"), - "Week": Timestamp("2010-12-25 00:00:00"), - "Hour": Timestamp("2011-01-01 00:00:00"), - "Minute": Timestamp("2011-01-01 00:00:00"), - "Second": Timestamp("2011-01-01 00:00:00"), - "Milli": Timestamp("2011-01-01 00:00:00"), - "Micro": Timestamp("2011-01-01 00:00:00"), - } - norm_expected.update(normalized) - sdt = datetime(2011, 1, 1, 9, 0) ndt = np.datetime64("2011-01-01 09:00")