Skip to content

Commit ef75390

Browse files
jbrockmendeljreback
authored andcommitted
Fix Series.__sub__ non-nano datetime64 (#18783)
1 parent f42ae78 commit ef75390

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

doc/source/whatsnew/v0.23.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ Reshaping
358358
Numeric
359359
^^^^^^^
360360

361-
-
361+
- Bug in :func:`Series.__sub__` subtracting a non-nanosecond ``np.datetime64`` object from a ``Series`` gave incorrect results (:issue:`7996`)
362362
-
363363
-
364364

pandas/core/ops.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
is_datetimelike_v_numeric,
2929
is_integer_dtype, is_categorical_dtype,
3030
is_object_dtype, is_timedelta64_dtype,
31-
is_datetime64_dtype, is_datetime64tz_dtype,
31+
is_datetime64_dtype, is_datetime64tz_dtype, is_datetime64_ns_dtype,
3232
is_bool_dtype, is_datetimetz,
3333
is_list_like, is_offsetlike,
3434
is_scalar,
@@ -527,6 +527,11 @@ def _convert_to_array(self, values, name=None, other=None):
527527
elif not (isinstance(values, (np.ndarray, ABCSeries)) and
528528
is_datetime64_dtype(values)):
529529
values = libts.array_to_datetime(values)
530+
elif (is_datetime64_dtype(values) and
531+
not is_datetime64_ns_dtype(values)):
532+
# GH#7996 e.g. np.datetime64('2013-01-01') is datetime64[D]
533+
values = values.astype('datetime64[ns]')
534+
530535
elif inferred_type in ('timedelta', 'timedelta64'):
531536
# have a timedelta, convert to to ns here
532537
values = to_timedelta(values, errors='coerce', box=False)

pandas/tests/series/test_operators.py

+27
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,33 @@ def test_operators_timedelta64_with_timedelta_invalid(self, scalar_td):
10041004

10051005

10061006
class TestDatetimeSeriesArithmetic(object):
1007+
@pytest.mark.parametrize(
1008+
'box, assert_func',
1009+
[(Series, tm.assert_series_equal),
1010+
(pd.Index, tm.assert_index_equal)])
1011+
def test_sub_datetime64_not_ns(self, box, assert_func):
1012+
# GH#7996
1013+
dt64 = np.datetime64('2013-01-01')
1014+
assert dt64.dtype == 'datetime64[D]'
1015+
1016+
obj = box(date_range('20130101', periods=3))
1017+
res = obj - dt64
1018+
expected = box([Timedelta(days=0), Timedelta(days=1),
1019+
Timedelta(days=2)])
1020+
assert_func(res, expected)
1021+
1022+
res = dt64 - obj
1023+
assert_func(res, -expected)
1024+
1025+
@pytest.mark.xfail(reason='GH#7996 datetime64 units not converted to nano')
1026+
def test_frame_sub_datetime64_not_ns(self):
1027+
df = pd.DataFrame(date_range('20130101', periods=3))
1028+
dt64 = np.datetime64('2013-01-01')
1029+
assert dt64.dtype == 'datetime64[D]'
1030+
res = df - dt64
1031+
expected = pd.DataFrame([Timedelta(days=0), Timedelta(days=1),
1032+
Timedelta(days=2)])
1033+
tm.assert_frame_equal(res, expected)
10071034

10081035
def test_operators_datetimelike(self):
10091036
def run_ops(ops, get_ser, test_ser):

0 commit comments

Comments
 (0)