Skip to content

Commit 298431f

Browse files
committed
BUG #31793 subtract datetime from Timestamp
1 parent 7f910b5 commit 298431f

File tree

3 files changed

+34
-19
lines changed

3 files changed

+34
-19
lines changed

pandas/_libs/tslibs/timestamps.pyx

+4-4
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,10 @@ cdef class _Timestamp(ABCTimestamp):
367367
else:
368368
self = type(other)(self)
369369

370-
# validate tz's
371-
if not tz_compare(self.tzinfo, other.tzinfo):
372-
raise TypeError("Timestamp subtraction must have the "
373-
"same timezones or no timezones")
370+
if (self.tzinfo is None) ^ (other.tzinfo is None):
371+
raise TypeError(
372+
"Cannot subtract offset-naive and offset-aware datetimes."
373+
)
374374

375375
# scalar Timestamp/datetime - Timestamp/datetime -> yields a
376376
# Timedelta

pandas/core/arrays/datetimes.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -717,11 +717,9 @@ def _sub_datetimelike_scalar(self, other):
717717
if other is NaT:
718718
return self - NaT
719719

720-
if not self._has_same_tz(other):
721-
# require tz compat
722-
raise TypeError(
723-
"Timestamp subtraction must have the same timezones or no timezones"
724-
)
720+
if (self.tzinfo is None) ^ (other.tzinfo is None):
721+
# require non-ambiguous timezones
722+
raise TypeError("Cannot subtract offset-naive and offset-aware datetimes.")
725723

726724
i8 = self.asi8
727725
result = checked_add_with_arr(i8, -other.value, arr_mask=self._isnan)

pandas/tests/arithmetic/test_timedelta64.py

+27-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Arithmetic tests for DataFrame/Series/Index/Array classes that should
22
# behave identically.
3-
from datetime import datetime, timedelta
3+
from datetime import datetime, timedelta, timezone
44

55
import numpy as np
66
import pytest
@@ -337,6 +337,8 @@ def test_subtraction_ops_with_tz(self):
337337
ts_tz2 = Timestamp("20130101").tz_localize("CET")
338338
dt_tz = ts_tz.to_pydatetime()
339339
td = Timedelta("1 days")
340+
ts_utc = Timestamp("2020-10-22T22:00:00+00:00")
341+
dt_utc = datetime(2020, 10, 22, 22, tzinfo=timezone.utc)
340342

341343
def _check(result, expected):
342344
assert result == expected
@@ -355,36 +357,51 @@ def _check(result, expected):
355357
expected = Timedelta("0 days")
356358
_check(result, expected)
357359

360+
result = ts_utc - dt_utc
361+
expected = Timedelta("0 days")
362+
_check(result, expected)
363+
364+
result = dt_tz - ts_tz2
365+
expected = Timedelta("0 days 06:00:00")
366+
_check(result, expected)
367+
368+
result = ts_tz2 - dt_tz
369+
expected = Timedelta("-1 days +18:00:00")
370+
_check(result, expected)
371+
372+
# gotta chedk this
358373
# tz mismatches
359-
msg = "Timestamp subtraction must have the same timezones or no timezones"
374+
msg = "Cannot subtract offset-naive and offset-aware datetimes."
360375
with pytest.raises(TypeError, match=msg):
361376
dt_tz - ts
362377
msg = "can't subtract offset-naive and offset-aware datetimes"
363378
with pytest.raises(TypeError, match=msg):
364379
dt_tz - dt
365-
msg = "Timestamp subtraction must have the same timezones or no timezones"
366-
with pytest.raises(TypeError, match=msg):
367-
dt_tz - ts_tz2
368380
msg = "can't subtract offset-naive and offset-aware datetimes"
369381
with pytest.raises(TypeError, match=msg):
370382
dt - dt_tz
371-
msg = "Timestamp subtraction must have the same timezones or no timezones"
383+
msg = "Cannot subtract offset-naive and offset-aware datetimes."
372384
with pytest.raises(TypeError, match=msg):
373385
ts - dt_tz
374386
with pytest.raises(TypeError, match=msg):
375387
ts_tz2 - ts
376388
with pytest.raises(TypeError, match=msg):
377389
ts_tz2 - dt
378-
with pytest.raises(TypeError, match=msg):
379-
ts_tz - ts_tz2
380390

381391
# with dti
382392
with pytest.raises(TypeError, match=msg):
383393
dti - ts_tz
384394
with pytest.raises(TypeError, match=msg):
385395
dti_tz - ts
386-
with pytest.raises(TypeError, match=msg):
387-
dti_tz - ts_tz2
396+
397+
result = dti_tz - ts_tz2
398+
expected = TimedeltaIndex(["0 days 06:00:00", "1 days 06:00:00", "2 days 06:00:00"])
399+
tm.assert_index_equal(result, expected)
400+
401+
402+
result = ts_tz2 - dti_tz
403+
expected = TimedeltaIndex(["-1 days +18:00:00", "-2 days +18:00:00", "-3 days +18:00:00"])
404+
tm.assert_index_equal(result, expected)
388405

389406
result = dti_tz - dt_tz
390407
expected = TimedeltaIndex(["0 days", "1 days", "2 days"])

0 commit comments

Comments
 (0)