Skip to content

Make TimedeltaIndex +/- pd.NaT return TimedeltaIndex #19139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 16, 2018
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.23.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ Other API Changes
- The default ``Timedelta`` constructor now accepts an ``ISO 8601 Duration`` string as an argument (:issue:`19040`)
- ``IntervalDtype`` now returns ``True`` when compared against ``'interval'`` regardless of subtype, and ``IntervalDtype.name`` now returns ``'interval'`` regardless of subtype (:issue:`18980`)
- :func:`Series.to_csv` now accepts a ``compression`` argument that works in the same way as the ``compression`` argument in :func:`DataFrame.to_csv` (:issue:`18958`)
- Addition or subtraction of ``NaT`` from :class:`TimedeltaIndex` will return ``TimedeltaIndex`` instead of ``DatetimeIndex`` (:issue:`19124`)

.. _whatsnew_0230.deprecations:

Expand Down
10 changes: 6 additions & 4 deletions pandas/core/indexes/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,8 @@ def _add_datelike(self, other):
# adding a timedeltaindex to a datetimelike
from pandas import Timestamp, DatetimeIndex
if other is NaT:
result = self._nat_new(box=False)
# GH#19124 pd.NaT is treated like a timedelta
return self._nat_new()
else:
other = Timestamp(other)
i8 = self.asi8
Expand All @@ -413,12 +414,13 @@ def _add_datelike(self, other):
return DatetimeIndex(result, name=self.name, copy=False)

def _sub_datelike(self, other):
from pandas import DatetimeIndex
# GH#19124 Timedelta - datetime is not in general well-defined.
# We make an exception for pd.NaT, which in this case quacks
# like a timedelta.
if other is NaT:
result = self._nat_new(box=False)
return self._nat_new()
else:
raise TypeError("cannot subtract a datelike from a TimedeltaIndex")
return DatetimeIndex(result, name=self.name, copy=False)

def _add_offset_array(self, other):
# Array/Index of DateOffset objects
Expand Down
30 changes: 23 additions & 7 deletions pandas/tests/scalar/test_nat.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,30 @@ def test_nat_arithmetic_index():
tm.assert_index_equal(left - right, exp)
tm.assert_index_equal(right - left, exp)

# timedelta
# timedelta # GH#19124
Copy link
Contributor

Choose a reason for hiding this comment

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

can you add similar testing for Series here as well

Copy link
Member Author

@jbrockmendel jbrockmendel Jan 9, 2018

Choose a reason for hiding this comment

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

Shoot this surfaces a new bug; I'll xfail for now.

tdi = TimedeltaIndex(['1 day', '2 day'], name='x')
exp = DatetimeIndex([NaT, NaT], name='x')
for (left, right) in [(NaT, tdi)]:
tm.assert_index_equal(left + right, exp)
tm.assert_index_equal(right + left, exp)
tm.assert_index_equal(left - right, exp)
tm.assert_index_equal(right - left, exp)
tdi_nat = TimedeltaIndex([NaT, NaT], name='x')

tm.assert_index_equal(tdi + NaT, tdi_nat)
tm.assert_index_equal(NaT + tdi, tdi_nat)
tm.assert_index_equal(tdi - NaT, tdi_nat)
tm.assert_index_equal(NaT - tdi, tdi_nat)


@pytest.mark.parametrize('box, assert_func', [
(TimedeltaIndex, tm.assert_index_equal),
pytest.param(Series, tm.assert_series_equal,
marks=pytest.mark.xfail(reason='NaT - Series returns NaT'))
])
def test_nat_arithmetic_td64_vector(box, assert_func):
# GH#19124
vec = box(['1 day', '2 day'], dtype='timedelta64[ns]')
box_nat = box([NaT, NaT], dtype='timedelta64[ns]')

assert_func(vec + NaT, box_nat)
assert_func(NaT + vec, box_nat)
assert_func(vec - NaT, box_nat)
assert_func(NaT - vec, box_nat)


def test_nat_pinned_docstrings():
Expand Down