Skip to content

Commit 4f000f5

Browse files
illegalnumbersaeltanawy
authored andcommitted
fix raise of TypeError when subtracting timedelta array (pandas-dev#22054)
closes pandas-dev#21980
1 parent bada277 commit 4f000f5

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed

doc/source/whatsnew/v0.24.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,7 @@ Timedelta
646646
- Bug in :class:`Series` with numeric dtype when adding or subtracting an an array or ``Series`` with ``timedelta64`` dtype (:issue:`22390`)
647647
- Bug in :class:`Index` with numeric dtype when multiplying or dividing an array with dtype ``timedelta64`` (:issue:`22390`)
648648
- Bug in :class:`TimedeltaIndex` incorrectly allowing indexing with ``Timestamp`` object (:issue:`20464`)
649+
- Fixed bug where subtracting :class:`Timedelta` from an object-dtyped array would raise ``TypeError`` (:issue:`21980`)
649650
-
650651
-
651652

pandas/_libs/tslibs/timedeltas.pyx

+5-3
Original file line numberDiff line numberDiff line change
@@ -541,10 +541,12 @@ def _binary_op_method_timedeltalike(op, name):
541541

542542
elif hasattr(other, 'dtype'):
543543
# nd-array like
544-
if other.dtype.kind not in ['m', 'M']:
545-
# raise rathering than letting numpy return wrong answer
544+
if other.dtype.kind in ['m', 'M']:
545+
return op(self.to_timedelta64(), other)
546+
elif other.dtype.kind == 'O':
547+
return np.array([op(self, x) for x in other])
548+
else:
546549
return NotImplemented
547-
return op(self.to_timedelta64(), other)
548550

549551
elif not _validate_ops_compat(other):
550552
return NotImplemented

pandas/tests/scalar/timedelta/test_arithmetic.py

+65
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,57 @@ def test_td_rsub_numeric_raises(self):
200200
with pytest.raises(TypeError):
201201
2.0 - td
202202

203+
def test_td_sub_timedeltalike_object_dtype_array(self):
204+
# GH 21980
205+
arr = np.array([Timestamp('20130101 9:01'),
206+
Timestamp('20121230 9:02')])
207+
exp = np.array([Timestamp('20121231 9:01'),
208+
Timestamp('20121229 9:02')])
209+
res = arr - pd.Timedelta('1D')
210+
tm.assert_numpy_array_equal(res, exp)
211+
212+
def test_td_sub_mixed_most_timedeltalike_object_dtype_array(self):
213+
# GH 21980
214+
now = pd.Timestamp.now()
215+
arr = np.array([now,
216+
pd.Timedelta('1D'),
217+
np.timedelta64(2, 'h')])
218+
exp = np.array([now - pd.Timedelta('1D'),
219+
pd.Timedelta('0D'),
220+
np.timedelta64(2, 'h') - pd.Timedelta('1D')])
221+
res = arr - pd.Timedelta('1D')
222+
tm.assert_numpy_array_equal(res, exp)
223+
224+
def test_td_rsub_mixed_most_timedeltalike_object_dtype_array(self):
225+
# GH 21980
226+
now = pd.Timestamp.now()
227+
arr = np.array([now,
228+
pd.Timedelta('1D'),
229+
np.timedelta64(2, 'h')])
230+
with pytest.raises(TypeError):
231+
pd.Timedelta('1D') - arr
232+
233+
@pytest.mark.parametrize('op', [operator.add, ops.radd])
234+
def test_td_add_timedeltalike_object_dtype_array(self, op):
235+
# GH 21980
236+
arr = np.array([Timestamp('20130101 9:01'),
237+
Timestamp('20121230 9:02')])
238+
exp = np.array([Timestamp('20130102 9:01'),
239+
Timestamp('20121231 9:02')])
240+
res = op(arr, pd.Timedelta('1D'))
241+
tm.assert_numpy_array_equal(res, exp)
242+
243+
@pytest.mark.parametrize('op', [operator.add, ops.radd])
244+
def test_td_add_mixed_timedeltalike_object_dtype_array(self, op):
245+
# GH 21980
246+
now = pd.Timestamp.now()
247+
arr = np.array([now,
248+
pd.Timedelta('1D')])
249+
exp = np.array([now + pd.Timedelta('1D'),
250+
pd.Timedelta('2D')])
251+
res = op(arr, pd.Timedelta('1D'))
252+
tm.assert_numpy_array_equal(res, exp)
253+
203254

204255
class TestTimedeltaMultiplicationDivision(object):
205256
"""
@@ -616,3 +667,17 @@ def test_rdivmod_invalid(self):
616667

617668
with pytest.raises(TypeError):
618669
divmod(np.array([22, 24]), td)
670+
671+
@pytest.mark.parametrize('op', [
672+
operator.mul,
673+
ops.rmul,
674+
operator.truediv,
675+
ops.rdiv,
676+
ops.rsub])
677+
@pytest.mark.parametrize('arr', [
678+
np.array([Timestamp('20130101 9:01'), Timestamp('20121230 9:02')]),
679+
np.array([pd.Timestamp.now(), pd.Timedelta('1D')])
680+
])
681+
def test_td_op_timedelta_timedeltalike_array(self, op, arr):
682+
with pytest.raises(TypeError):
683+
op(arr, pd.Timedelta('1D'))

0 commit comments

Comments
 (0)