From 97c68bd852d81ca18b91aaf51fee36e1c078f934 Mon Sep 17 00:00:00 2001 From: Ben Nelson Date: Wed, 25 Jul 2018 13:41:55 -0600 Subject: [PATCH] fix raise of TypeError when subtracting timedelta array fixes #21980 --- doc/source/whatsnew/v0.24.0.txt | 2 +- pandas/_libs/tslibs/timedeltas.pyx | 10 +++++++--- pandas/tests/series/test_timeseries.py | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 43e380abd8bb53..fc046e90e8503d 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -441,7 +441,7 @@ Datetimelike Timedelta ^^^^^^^^^ -- +- Fixed bug where array of timestamp and deltas raised a TypeError: unsupported operand type(s) for -: 'numpy.ndarray' and 'Timedelta' (:issue:`21980`) - - diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index f7a6cf0c6dafc2..509f8b71d92094 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -542,10 +542,14 @@ def _binary_op_method_timedeltalike(op, name): elif hasattr(other, 'dtype'): # nd-array like - if other.dtype.kind not in ['m', 'M']: + if other.dtype.kind not in ['m', 'M', 'O']: # raise rathering than letting numpy return wrong answer return NotImplemented - return op(self.to_timedelta64(), other) + try: + converted_other = other.astype('datetime64[ns]') + return op(self.to_timedelta64(), converted_other) + except: + return NotImplemented elif not _validate_ops_compat(other): return NotImplemented @@ -929,7 +933,7 @@ cdef class _Timedelta(timedelta): def nanoseconds(self): """ Return the number of nanoseconds (n), where 0 <= n < 1 microsecond. - + Returns ------- int diff --git a/pandas/tests/series/test_timeseries.py b/pandas/tests/series/test_timeseries.py index 376b4d71f81e8a..853ea70aecaeca 100644 --- a/pandas/tests/series/test_timeseries.py +++ b/pandas/tests/series/test_timeseries.py @@ -1012,3 +1012,22 @@ def test_get_level_values_box(self): index = MultiIndex(levels=levels, labels=labels) assert isinstance(index.get_level_values(0)[0], Timestamp) + + def test_diff_sub_timedelta(self): + # GH 21980 + arr = np.array([Timestamp('20130101 9:01'), + Timestamp('20121230 9:02')]) + exp = np.array([Timestamp('20121231 9:01'), + Timestamp('20121229 9:02')]).astype('datetime64[ns]') + res = arr - pd.Timedelta('1D') + tm.assert_numpy_array_equal(res, exp) + + def test_diff_sub_timedelta_mixed(self): + # GH 21980 + now = pd.Timestamp.now() + arr = np.array([now, + Timestamp('20121230 9:02')]) + exp = np.array([now - pd.Timedelta('1D'), + Timestamp('20121229 9:02')]).astype('datetime64[ns]') + res = arr - pd.Timedelta('1D') + tm.assert_numpy_array_equal(res, exp)