Skip to content

Commit c46a7de

Browse files
committed
Merge branch 'master' of https://github.com/pandas-dev/pandas into fix_33956
2 parents 5683d4b + b465714 commit c46a7de

File tree

10 files changed

+256
-261
lines changed

10 files changed

+256
-261
lines changed

pandas/_libs/tslibs/c_timestamp.pyx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,11 @@ cdef class _Timestamp(datetime):
251251
# delta --> offsets.Tick
252252
# logic copied from delta_to_nanoseconds to prevent circular import
253253
if hasattr(other, 'nanos'):
254+
# Tick
254255
nanos = other.nanos
255256
elif hasattr(other, 'delta'):
256-
nanos = other.delta
257+
# pd.Timedelta
258+
nanos = other.value
257259
elif PyDelta_Check(other):
258260
nanos = (other.days * 24 * 60 * 60 * 1000000 +
259261
other.seconds * 1000000 +
@@ -273,15 +275,7 @@ cdef class _Timestamp(datetime):
273275
dtype=object,
274276
)
275277

276-
# index/series like
277-
elif hasattr(other, '_typ'):
278-
return NotImplemented
279-
280-
result = datetime.__add__(self, other)
281-
if PyDateTime_Check(result):
282-
result = type(self)(result)
283-
result.nanosecond = self.nanosecond
284-
return result
278+
return NotImplemented
285279

286280
def __sub__(self, other):
287281

@@ -301,9 +295,6 @@ cdef class _Timestamp(datetime):
301295
[self - other[n] for n in range(len(other))],
302296
dtype=object,
303297
)
304-
305-
typ = getattr(other, '_typ', None)
306-
if typ is not None:
307298
return NotImplemented
308299

309300
if other is NaT:
@@ -339,6 +330,8 @@ cdef class _Timestamp(datetime):
339330
"to datetime.datetime with 'Timestamp.to_pydatetime()' "
340331
"before subtracting."
341332
) from err
333+
# We get here in stata tests, fall back to stdlib datetime
334+
# method and return stdlib timedelta object
342335
pass
343336
elif is_datetime64_object(self):
344337
# GH#28286 cython semantics for __rsub__, `other` is actually

pandas/_libs/tslibs/conversion.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ cdef convert_to_tsobject(object ts, object tz, object unit,
265265
ts = <int64_t>ts
266266
except OverflowError:
267267
# GH#26651 re-raise as OutOfBoundsDatetime
268-
raise OutOfBoundsDatetime(ts)
268+
raise OutOfBoundsDatetime(f"Out of bounds nanosecond timestamp {ts}")
269269
if ts == NPY_NAT:
270270
obj.value = NPY_NAT
271271
else:

pandas/_libs/tslibs/timedeltas.pyx

Lines changed: 57 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ PyDateTime_IMPORT
1818
cimport pandas._libs.tslibs.util as util
1919
from pandas._libs.tslibs.util cimport (
2020
is_timedelta64_object, is_datetime64_object, is_integer_object,
21-
is_float_object)
21+
is_float_object, is_array
22+
)
2223

2324
from pandas._libs.tslibs.c_timestamp cimport _Timestamp
2425

@@ -606,7 +607,7 @@ def _binary_op_method_timedeltalike(op, name):
606607
# We are implicitly requiring the canonical behavior to be
607608
# defined by Timestamp methods.
608609

609-
elif hasattr(other, 'dtype'):
610+
elif is_array(other):
610611
# nd-array like
611612
if other.dtype.kind in ['m', 'M']:
612613
return op(self.to_timedelta64(), other)
@@ -1347,113 +1348,64 @@ class Timedelta(_Timedelta):
13471348
__rsub__ = _binary_op_method_timedeltalike(lambda x, y: y - x, '__rsub__')
13481349

13491350
def __mul__(self, other):
1350-
if hasattr(other, '_typ'):
1351-
# Series, DataFrame, ...
1352-
if other._typ == 'dateoffset' and hasattr(other, 'delta'):
1353-
# Tick offset; this op will raise TypeError
1354-
return other.delta * self
1355-
return NotImplemented
1351+
if is_integer_object(other) or is_float_object(other):
1352+
return Timedelta(other * self.value, unit='ns')
13561353

1357-
elif util.is_nan(other):
1358-
# i.e. np.nan, but also catch np.float64("NaN") which would
1359-
# otherwise get caught by the hasattr(other, "dtype") branch
1360-
# incorrectly return a np.timedelta64 object.
1361-
return NaT
1362-
1363-
elif hasattr(other, 'dtype'):
1354+
elif is_array(other):
13641355
# ndarray-like
13651356
return other * self.to_timedelta64()
13661357

1367-
elif other is NaT:
1368-
raise TypeError('Cannot multiply Timedelta with NaT')
1369-
1370-
elif not (is_integer_object(other) or is_float_object(other)):
1371-
# only integers and floats allowed
1372-
return NotImplemented
1373-
1374-
return Timedelta(other * self.value, unit='ns')
1358+
return NotImplemented
13751359

13761360
__rmul__ = __mul__
13771361

13781362
def __truediv__(self, other):
1379-
if hasattr(other, '_typ'):
1380-
# Series, DataFrame, ...
1381-
if other._typ == 'dateoffset' and hasattr(other, 'delta'):
1382-
# Tick offset
1383-
return self / other.delta
1384-
return NotImplemented
1385-
1386-
elif is_timedelta64_object(other):
1387-
# convert to Timedelta below
1388-
pass
1389-
1390-
elif util.is_nan(other):
1391-
# i.e. np.nan, but also catch np.float64("NaN") which would
1392-
# otherwise get caught by the hasattr(other, "dtype") branch
1393-
# incorrectly return a np.timedelta64 object.
1394-
return NaT
1395-
1396-
elif hasattr(other, 'dtype'):
1397-
return self.to_timedelta64() / other
1363+
if _should_cast_to_timedelta(other):
1364+
# We interpret NaT as timedelta64("NaT")
1365+
other = Timedelta(other)
1366+
if other is NaT:
1367+
return np.nan
1368+
return self.value / float(other.value)
13981369

13991370
elif is_integer_object(other) or is_float_object(other):
14001371
# integers or floats
14011372
return Timedelta(self.value / other, unit='ns')
14021373

1403-
elif not _validate_ops_compat(other):
1404-
return NotImplemented
1374+
elif is_array(other):
1375+
return self.to_timedelta64() / other
14051376

1406-
other = Timedelta(other)
1407-
if other is NaT:
1408-
return np.nan
1409-
return self.value / float(other.value)
1377+
return NotImplemented
14101378

14111379
def __rtruediv__(self, other):
1412-
if hasattr(other, '_typ'):
1413-
# Series, DataFrame, ...
1414-
if other._typ == 'dateoffset' and hasattr(other, 'delta'):
1415-
# Tick offset
1416-
return other.delta / self
1417-
return NotImplemented
1418-
1419-
elif is_timedelta64_object(other):
1420-
# convert to Timedelta below
1421-
pass
1422-
1423-
elif util.is_nan(other):
1424-
# i.e. np.nan or np.float64("NaN")
1425-
raise TypeError("Cannot divide float by Timedelta")
1380+
if _should_cast_to_timedelta(other):
1381+
# We interpret NaT as timedelta64("NaT")
1382+
other = Timedelta(other)
1383+
if other is NaT:
1384+
return np.nan
1385+
return float(other.value) / self.value
14261386

1427-
elif hasattr(other, 'dtype'):
1387+
elif is_array(other):
14281388
if other.dtype.kind == "O":
14291389
# GH#31869
14301390
return np.array([x / self for x in other])
14311391
return other / self.to_timedelta64()
14321392

1433-
elif not _validate_ops_compat(other):
1434-
return NotImplemented
1435-
1436-
other = Timedelta(other)
1437-
if other is NaT:
1438-
# In this context we treat NaT as timedelta-like
1439-
return np.nan
1440-
return float(other.value) / self.value
1393+
return NotImplemented
14411394

14421395
def __floordiv__(self, other):
14431396
# numpy does not implement floordiv for timedelta64 dtype, so we cannot
14441397
# just defer
1445-
if hasattr(other, '_typ'):
1446-
# Series, DataFrame, ...
1447-
if other._typ == 'dateoffset' and hasattr(other, 'delta'):
1448-
# Tick offset
1449-
return self // other.delta
1450-
return NotImplemented
1398+
if _should_cast_to_timedelta(other):
1399+
# We interpret NaT as timedelta64("NaT")
1400+
other = Timedelta(other)
1401+
if other is NaT:
1402+
return np.nan
1403+
return self.value // other.value
14511404

1452-
elif is_timedelta64_object(other):
1453-
# convert to Timedelta below
1454-
pass
1405+
elif is_integer_object(other) or is_float_object(other):
1406+
return Timedelta(self.value // other, unit='ns')
14551407

1456-
elif hasattr(other, 'dtype'):
1408+
elif is_array(other):
14571409
if other.dtype.kind == 'm':
14581410
# also timedelta-like
14591411
return _broadcast_floordiv_td64(self.value, other, _floordiv)
@@ -1465,50 +1417,27 @@ class Timedelta(_Timedelta):
14651417

14661418
raise TypeError(f'Invalid dtype {other.dtype} for __floordiv__')
14671419

1468-
elif is_integer_object(other) or is_float_object(other):
1469-
return Timedelta(self.value // other, unit='ns')
1470-
1471-
elif not _validate_ops_compat(other):
1472-
return NotImplemented
1473-
1474-
other = Timedelta(other)
1475-
if other is NaT:
1476-
return np.nan
1477-
return self.value // other.value
1420+
return NotImplemented
14781421

14791422
def __rfloordiv__(self, other):
14801423
# numpy does not implement floordiv for timedelta64 dtype, so we cannot
14811424
# just defer
1482-
if hasattr(other, '_typ'):
1483-
# Series, DataFrame, ...
1484-
if other._typ == 'dateoffset' and hasattr(other, 'delta'):
1485-
# Tick offset
1486-
return other.delta // self
1487-
return NotImplemented
1488-
1489-
elif is_timedelta64_object(other):
1490-
# convert to Timedelta below
1491-
pass
1425+
if _should_cast_to_timedelta(other):
1426+
# We interpret NaT as timedelta64("NaT")
1427+
other = Timedelta(other)
1428+
if other is NaT:
1429+
return np.nan
1430+
return other.value // self.value
14921431

1493-
elif hasattr(other, 'dtype'):
1432+
elif is_array(other):
14941433
if other.dtype.kind == 'm':
14951434
# also timedelta-like
14961435
return _broadcast_floordiv_td64(self.value, other, _rfloordiv)
14971436

14981437
# Includes integer array // Timedelta, disallowed in GH#19761
14991438
raise TypeError(f'Invalid dtype {other.dtype} for __floordiv__')
15001439

1501-
elif is_float_object(other) and util.is_nan(other):
1502-
# i.e. np.nan
1503-
return NotImplemented
1504-
1505-
elif not _validate_ops_compat(other):
1506-
return NotImplemented
1507-
1508-
other = Timedelta(other)
1509-
if other is NaT:
1510-
return np.nan
1511-
return other.value // self.value
1440+
return NotImplemented
15121441

15131442
def __mod__(self, other):
15141443
# Naive implementation, room for optimization
@@ -1529,6 +1458,21 @@ class Timedelta(_Timedelta):
15291458
return div, other - div * self
15301459

15311460

1461+
cdef bint is_any_td_scalar(object obj):
1462+
return (
1463+
PyDelta_Check(obj) or is_timedelta64_object(obj) or isinstance(obj, Tick)
1464+
)
1465+
1466+
1467+
cdef bint _should_cast_to_timedelta(object obj):
1468+
"""
1469+
Should we treat this object as a Timedelta for the purpose of a binary op
1470+
"""
1471+
return (
1472+
is_any_td_scalar(obj) or obj is None or obj is NaT or isinstance(obj, str)
1473+
)
1474+
1475+
15321476
cdef _floordiv(int64_t value, right):
15331477
return value // right
15341478

0 commit comments

Comments
 (0)