Skip to content

Commit 8c3c9e3

Browse files
authored
BUG: DatetimeArray-datetimelike mixed resos (#48894)
1 parent 21ad93b commit 8c3c9e3

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

pandas/_libs/tslibs/timestamps.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ _DatetimeT = TypeVar("_DatetimeT", bound=datetime)
2727
def integer_op_not_supported(obj: object) -> TypeError: ...
2828

2929
class Timestamp(datetime):
30+
_reso: int
3031
min: ClassVar[Timestamp]
3132
max: ClassVar[Timestamp]
3233

pandas/core/arrays/datetimelike.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,14 @@ def _sub_datetimelike_scalar(self, other: datetime | np.datetime64):
12091209
return self - NaT
12101210

12111211
other = Timestamp(other)
1212+
1213+
if other._reso != self._reso:
1214+
if other._reso < self._reso:
1215+
other = other._as_unit(self._unit)
1216+
else:
1217+
unit = npy_unit_to_abbrev(other._reso)
1218+
self = self._as_unit(unit)
1219+
12121220
return self._sub_datetimelike(other)
12131221

12141222
@final
@@ -1221,6 +1229,13 @@ def _sub_datetime_arraylike(self, other):
12211229

12221230
self = cast("DatetimeArray", self)
12231231
other = ensure_wrapped_if_datetimelike(other)
1232+
1233+
if other._reso != self._reso:
1234+
if other._reso < self._reso:
1235+
other = other._as_unit(self._unit)
1236+
else:
1237+
self = self._as_unit(other._unit)
1238+
12241239
return self._sub_datetimelike(other)
12251240

12261241
@final

pandas/tests/arrays/test_datetimes.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
import pandas as pd
1515
import pandas._testing as tm
16-
from pandas.core.arrays import DatetimeArray
16+
from pandas.core.arrays import (
17+
DatetimeArray,
18+
TimedeltaArray,
19+
)
1720

1821

1922
class TestNonNano:
@@ -218,6 +221,32 @@ def test_add_mismatched_reso_doesnt_downcast(self):
218221
# (so we _could_ downcast to unit="s"), we do not.
219222
assert res._unit == "us"
220223

224+
def test_sub_datetimelike_scalar_mismatch(self):
225+
dti = pd.date_range("2016-01-01", periods=3)
226+
dta = dti._data._as_unit("us")
227+
228+
ts = dta[0]._as_unit("s")
229+
230+
result = dta - ts
231+
expected = (dti - dti[0])._data._as_unit("us")
232+
assert result.dtype == "m8[us]"
233+
tm.assert_extension_array_equal(result, expected)
234+
235+
def test_sub_datetime64_reso_mismatch(self):
236+
dti = pd.date_range("2016-01-01", periods=3)
237+
left = dti._data._as_unit("s")
238+
right = left._as_unit("ms")
239+
240+
result = left - right
241+
exp_values = np.array([0, 0, 0], dtype="m8[ms]")
242+
expected = TimedeltaArray._simple_new(
243+
exp_values,
244+
dtype=exp_values.dtype,
245+
)
246+
tm.assert_extension_array_equal(result, expected)
247+
result2 = right - left
248+
tm.assert_extension_array_equal(result2, expected)
249+
221250

222251
class TestDatetimeArrayComparisons:
223252
# TODO: merge this into tests/arithmetic/test_datetime64 once it is

0 commit comments

Comments
 (0)