Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: Fixed ignoring of nanoseconds when adding to series #47856 #48008

Merged
merged 8 commits into from
Aug 10, 2022
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ Datetimelike
- Bug in :meth:`DatetimeIndex.resolution` incorrectly returning "day" instead of "nanosecond" for nanosecond-resolution indexes (:issue:`46903`)
- Bug in :class:`Timestamp` with an integer or float value and ``unit="Y"`` or ``unit="M"`` giving slightly-wrong results (:issue:`47266`)
- Bug in :class:`.DatetimeArray` construction when passed another :class:`.DatetimeArray` and ``freq=None`` incorrectly inferring the freq from the given array (:issue:`47296`)
- Bug when adding a :class:`DateOffset` to a :class:`Series` would not add the ``nanoseconds`` field (:issue:`47856`)
-

Timedelta
Expand Down
11 changes: 8 additions & 3 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,8 @@ _relativedelta_kwds = {"years", "months", "weeks", "days", "year", "month",

cdef _determine_offset(kwds):
# timedelta is used for sub-daily plural offsets and all singular
# offsets relativedelta is used for plural offsets of daily length or
# more nanosecond(s) are handled by apply_wraps
# offsets, relativedelta is used for plural offsets of daily length or
# more, nanosecond(s) are handled by apply_wraps
kwds_no_nanos = dict(
(k, v) for k, v in kwds.items()
if k not in ('nanosecond', 'nanoseconds')
Expand Down Expand Up @@ -1157,7 +1157,12 @@ cdef class RelativeDeltaOffset(BaseOffset):
return dt64other
elif not self._use_relativedelta and hasattr(self, "_offset"):
# timedelta
delta = Timedelta(self._offset * self.n)
num_nano = getattr(self, "nanoseconds", 0)
if num_nano != 0:
rem_nano = Timedelta(nanoseconds=num_nano)
delta = Timedelta((self._offset + rem_nano) * self.n)
else:
delta = Timedelta(self._offset * self.n)
td = (<_Timedelta>delta)._as_reso(reso)
return dt64other + td
else:
Expand Down
26 changes: 25 additions & 1 deletion pandas/tests/tseries/offsets/test_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

from pandas import (
DatetimeIndex,
Series,
date_range,
)
import pandas._testing as tm
Expand Down Expand Up @@ -987,7 +988,7 @@ def test_dateoffset_add_sub(offset_kwargs, expected_arg):
assert result == expected


def test_dataoffset_add_sub_timestamp_with_nano():
def test_dateoffset_add_sub_timestamp_with_nano():
offset = DateOffset(minutes=2, nanoseconds=9)
ts = Timestamp(4)
result = ts + offset
Expand Down Expand Up @@ -1032,3 +1033,26 @@ def test_construct_int_arg_no_kwargs_assumed_days(n):
result = Timestamp(2022, 1, 2) + offset
expected = Timestamp(2022, 1, 2 + n)
assert result == expected


@pytest.mark.parametrize(
"offset, expected",
[
(
DateOffset(minutes=7, nanoseconds=18),
Timestamp("2022-01-01 00:07:00.000000018"),
),
(DateOffset(nanoseconds=3), Timestamp("2022-01-01 00:00:00.000000003")),
],
)
def test_dateoffset_add_sub_timestamp_series_with_nano(offset, expected):
# GH 47856
start_time = Timestamp("2022-01-01")
teststamp = start_time
testseries = Series([start_time])
testseries = testseries + offset
assert testseries[0] == expected
testseries -= offset
assert testseries[0] == teststamp
testseries = offset + testseries
assert testseries[0] == expected