Skip to content

Commit

Permalink
Backport PR #57536 on branch 2.2.x (BUG: dt64 + DateOffset with milli…
Browse files Browse the repository at this point in the history
…seconds) (#57537)

Backport PR #57536: BUG: dt64 + DateOffset with milliseconds

Co-authored-by: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com>
  • Loading branch information
meeseeksmachine and mroeschke authored Feb 20, 2024
1 parent 9b1ce06 commit 0b49cf3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.2.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Fixed regressions
- Fixed regression in :meth:`Series.astype` introducing decimals when converting from integer with missing values to string dtype (:issue:`57418`)
- Fixed regression in :meth:`Series.pct_change` raising a ``ValueError`` for an empty :class:`Series` (:issue:`57056`)
- Fixed regression in :meth:`Series.to_numpy` when dtype is given as float and the data contains NaNs (:issue:`57121`)
- Fixed regression in addition or subtraction of :class:`DateOffset` objects with millisecond components to ``datetime64`` :class:`Index`, :class:`Series`, or :class:`DataFrame` (:issue:`57529`)

.. ---------------------------------------------------------------------------
.. _whatsnew_221.bug_fixes:
Expand Down
15 changes: 14 additions & 1 deletion pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1458,13 +1458,22 @@ cdef class RelativeDeltaOffset(BaseOffset):
"minutes",
"seconds",
"microseconds",
"milliseconds",
}
# relativedelta/_offset path only valid for base DateOffset
if self._use_relativedelta and set(kwds).issubset(relativedelta_fast):
td_args = {
"days",
"hours",
"minutes",
"seconds",
"microseconds",
"milliseconds"
}
td_kwds = {
key: val
for key, val in kwds.items()
if key in ["days", "hours", "minutes", "seconds", "microseconds"]
if key in td_args
}
if "weeks" in kwds:
days = td_kwds.get("days", 0)
Expand All @@ -1474,6 +1483,8 @@ cdef class RelativeDeltaOffset(BaseOffset):
delta = Timedelta(**td_kwds)
if "microseconds" in kwds:
delta = delta.as_unit("us")
elif "milliseconds" in kwds:
delta = delta.as_unit("ms")
else:
delta = delta.as_unit("s")
else:
Expand All @@ -1491,6 +1502,8 @@ cdef class RelativeDeltaOffset(BaseOffset):
delta = Timedelta(self._offset * self.n)
if "microseconds" in kwds:
delta = delta.as_unit("us")
elif "milliseconds" in kwds:
delta = delta.as_unit("ms")
else:
delta = delta.as_unit("s")
return delta
Expand Down
32 changes: 32 additions & 0 deletions pandas/tests/arithmetic/test_datetime64.py
Original file line number Diff line number Diff line change
Expand Up @@ -1586,6 +1586,38 @@ def test_dti_add_sub_nonzero_mth_offset(
expected = tm.box_expected(expected, box_with_array, False)
tm.assert_equal(result, expected)

def test_dt64arr_series_add_DateOffset_with_milli(self):
# GH 57529
dti = DatetimeIndex(
[
"2000-01-01 00:00:00.012345678",
"2000-01-31 00:00:00.012345678",
"2000-02-29 00:00:00.012345678",
],
dtype="datetime64[ns]",
)
result = dti + DateOffset(milliseconds=4)
expected = DatetimeIndex(
[
"2000-01-01 00:00:00.016345678",
"2000-01-31 00:00:00.016345678",
"2000-02-29 00:00:00.016345678",
],
dtype="datetime64[ns]",
)
tm.assert_index_equal(result, expected)

result = dti + DateOffset(days=1, milliseconds=4)
expected = DatetimeIndex(
[
"2000-01-02 00:00:00.016345678",
"2000-02-01 00:00:00.016345678",
"2000-03-01 00:00:00.016345678",
],
dtype="datetime64[ns]",
)
tm.assert_index_equal(result, expected)


class TestDatetime64OverflowHandling:
# TODO: box + de-duplicate
Expand Down

0 comments on commit 0b49cf3

Please sign in to comment.