Skip to content

Commit b54c622

Browse files
committed
BUG: Fix dt64[non_nano] + offset rounding
1 parent 4ffde3e commit b54c622

File tree

1 file changed

+24
-40
lines changed

1 file changed

+24
-40
lines changed

pandas/core/arrays/datetimes.py

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,8 @@ def _add_offset(self, offset: BaseOffset) -> Self:
802802
else:
803803
values = self
804804

805+
units = ["ns", "us", "ms", "s"]
806+
805807
try:
806808
res_values = offset._apply_array(values._ndarray)
807809
if res_values.dtype.kind == "i":
@@ -814,45 +816,27 @@ def _add_offset(self, offset: BaseOffset) -> Self:
814816
PerformanceWarning,
815817
stacklevel=find_stack_level(),
816818
)
817-
818819
# Handle non-vectorized DateOffsets with both calendar and
819820
# timedelta parts, preserving time resolution.
820-
if getattr(offset, "offset", None):
821-
try:
822-
kwds = offset.kwds.copy()
823-
if "offset" in kwds:
824-
del kwds["offset"]
825-
base_offset = type(offset)(**kwds)
826-
result = self._add_offset(base_offset) + offset.offset
827-
828-
offset_td = Timedelta(offset.offset)
829-
offset_unit = offset_td.unit
830-
if offset_unit == "ns":
831-
res_str = offset_td.resolution_string
832-
if res_str in ["ms", "us", "s"]:
833-
offset_unit = res_str
834-
835-
units = ["ns", "us", "ms", "s"]
836-
if self.unit in units and offset_unit in units:
837-
idx_self = units.index(self.unit)
838-
idx_offset = units.index(offset_unit)
839-
res_unit = units[min(idx_self, idx_offset)]
840-
return result.as_unit(res_unit)
841-
842-
return result
843-
except Exception:
844-
pass
845-
846-
res_values = self.astype("O") + offset
847-
result = type(self)._from_sequence(res_values, dtype=self.dtype)
821+
values_ns = values.as_unit("ns") if values.unit != "ns" else values
822+
res_values = np.array([ts + offset for ts in values_ns], dtype=object)
823+
824+
res_unit = self.unit
825+
826+
off = getattr(offset, "offset", None)
827+
if off is not None:
828+
offset_td = Timedelta(off)
829+
if offset_td.value != 0:
830+
offset_unit = offset_td.resolution_string
831+
if self.unit in units and offset_unit in units:
832+
idx_self = units.index(self.unit)
833+
idx_offset = units.index(offset_unit)
834+
res_unit = units[min(idx_self, idx_offset)]
835+
836+
dtype = np.dtype(f"datetime64[{res_unit}]")
837+
result = type(self)._from_sequence(res_values, dtype=dtype)
848838

849839
else:
850-
units = [
851-
"ns",
852-
"us",
853-
"ms",
854-
"s",
855-
]
856840
res_unit = self.unit
857841
if type(offset) is DateOffset:
858842
if "nanoseconds" in offset.kwds:
@@ -869,12 +853,12 @@ def _add_offset(self, offset: BaseOffset) -> Self:
869853
result = type(self)._simple_new(res_values, dtype=res_values.dtype)
870854
result = result.as_unit(res_unit)
871855

872-
if offset.normalize:
873-
result = result.normalize()
874-
result._freq = None
856+
if offset.normalize:
857+
result = result.normalize()
858+
result._freq = None
875859

876-
if self.tz is not None:
877-
result = result.tz_localize(self.tz)
860+
if self.tz is not None:
861+
result = result.tz_localize(self.tz)
878862

879863
return result
880864

0 commit comments

Comments
 (0)