Skip to content

Commit 7627cca

Browse files
jbrockmendeljreback
authored andcommitted
check for datetime+period addition (#18524)
1 parent e459658 commit 7627cca

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

doc/source/whatsnew/v0.22.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,5 @@ Other
208208

209209
- Improved error message when attempting to use a Python keyword as an identifier in a numexpr query (:issue:`18221`)
210210
- Fixed a bug where creating a Series from an array that contains both tz-naive and tz-aware values will result in a Series whose dtype is tz-aware instead of object (:issue:`16406`)
211+
- Adding a ``Period`` object to a ``datetime`` or ``Timestamp`` object will now correctly raise a ``TypeError`` (:issue:`17983`)
211212
-

pandas/_libs/period.pyx

+14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ from pandas.compat import PY2
1717

1818
cimport cython
1919

20+
from cpython.datetime cimport PyDateTime_Check, PyDateTime_IMPORT
21+
# import datetime C API
22+
PyDateTime_IMPORT
23+
2024
from tslibs.np_datetime cimport (pandas_datetimestruct,
2125
dtstruct_to_dt64, dt64_to_dtstruct,
2226
is_leapyear)
@@ -647,9 +651,19 @@ cdef class _Period(object):
647651
elif util.is_integer_object(other):
648652
ordinal = self.ordinal + other * self.freq.n
649653
return Period(ordinal=ordinal, freq=self.freq)
654+
elif (PyDateTime_Check(other) or
655+
is_period_object(other) or util.is_datetime64_object(other)):
656+
# can't add datetime-like
657+
# GH#17983
658+
sname = type(self).__name__
659+
oname = type(other).__name__
660+
raise TypeError("unsupported operand type(s) for +: '{self}' "
661+
"and '{other}'".format(self=sname,
662+
other=oname))
650663
else: # pragma: no cover
651664
return NotImplemented
652665
elif is_period_object(other):
666+
# this can be reached via __radd__ because of cython rules
653667
return other + self
654668
else:
655669
return NotImplemented

pandas/tests/scalar/test_period.py

+23
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,29 @@ def test_add_raises(self):
10381038
with tm.assert_raises_regex(TypeError, msg):
10391039
dt1 + dt2
10401040

1041+
boxes = [lambda x: x, lambda x: pd.Series([x]), lambda x: pd.Index([x])]
1042+
1043+
@pytest.mark.parametrize('lbox', boxes)
1044+
@pytest.mark.parametrize('rbox', boxes)
1045+
def test_add_timestamp_raises(self, rbox, lbox):
1046+
# GH # 17983
1047+
ts = pd.Timestamp('2017')
1048+
per = pd.Period('2017', freq='M')
1049+
1050+
# We may get a different message depending on which class raises
1051+
# the error.
1052+
msg = (r"cannot add|unsupported operand|"
1053+
r"can only operate on a|incompatible type|"
1054+
r"ufunc add cannot use operands")
1055+
with tm.assert_raises_regex(TypeError, msg):
1056+
lbox(ts) + rbox(per)
1057+
1058+
with tm.assert_raises_regex(TypeError, msg):
1059+
lbox(per) + rbox(ts)
1060+
1061+
with tm.assert_raises_regex(TypeError, msg):
1062+
lbox(per) + rbox(per)
1063+
10411064
def test_sub(self):
10421065
dt1 = Period('2011-01-01', freq='D')
10431066
dt2 = Period('2011-01-15', freq='D')

0 commit comments

Comments
 (0)