Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v0.22.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ Reshaping
Numeric
^^^^^^^

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

Expand Down
7 changes: 6 additions & 1 deletion pandas/core/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
is_datetimelike_v_numeric,
is_integer_dtype, is_categorical_dtype,
is_object_dtype, is_timedelta64_dtype,
is_datetime64_dtype, is_datetime64tz_dtype,
is_datetime64_dtype, is_datetime64tz_dtype, is_datetime64_ns_dtype,
is_bool_dtype, is_datetimetz,
is_list_like,
is_scalar,
Expand Down Expand Up @@ -497,6 +497,11 @@ def _convert_to_array(self, values, name=None, other=None):
elif not (isinstance(values, (np.ndarray, ABCSeries)) and
is_datetime64_dtype(values)):
values = libts.array_to_datetime(values)
elif (is_datetime64_dtype(values) and
not is_datetime64_ns_dtype(values)):
# GH#7996 e.g. np.datetime64('2013-01-01') is datetime64[D]
values = values.astype('datetime64[ns]')

elif inferred_type in ('timedelta', 'timedelta64'):
# have a timedelta, convert to to ns here
values = to_timedelta(values, errors='coerce', box=False)
Expand Down
32 changes: 32 additions & 0 deletions pandas/tests/series/test_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,38 @@
from .common import TestData


class TestDatetimeLikeArithmetic(object):
def test_sub_datetime64_not_ns(self):
# GH#7996
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameterize this

ser = Series(date_range('20130101', periods=3))
dt64 = np.datetime64('2013-01-01')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test with a tz-aware as well (as I think that may hit your path, unless its getting caught earlier)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It gets caught earlier: tz compat raises ValueError in ops._validate

assert dt64.dtype == 'datetime64[D]'
res = ser - dt64
expected = pd.Series([Timedelta(days=0), Timedelta(days=1),
Timedelta(days=2)])
tm.assert_series_equal(res, expected)

res = dt64 - ser
tm.assert_series_equal(res, -expected)

dti = pd.DatetimeIndex(ser)
res = dti - dt64
tm.assert_index_equal(res, pd.Index(expected))

res = dt64 - dti
tm.assert_index_equal(res, pd.Index(-expected))

@pytest.mark.xfail(reason='GH#7996 datetime64 units not converted to nano')
def test_frame_sub_datetime64_not_ns(self):
df = pd.DataFrame(date_range('20130101', periods=3))
dt64 = np.datetime64('2013-01-01')
assert dt64.dtype == 'datetime64[D]'
res = df - dt64
expected = pd.DataFrame([Timedelta(days=0), Timedelta(days=1),
Timedelta(days=2)])
tm.assert_frame_equal(res, expected)


class TestSeriesOperators(TestData):

def test_series_comparison_scalars(self):
Expand Down