Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 4 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ Bug fixes
- Saving files with times encoded with reference dates with timezones
(e.g. '2000-01-01T00:00:00-05:00') no longer raises an error
(:issue:`2649`). By `Spencer Clark <https://github.com/spencerkclark>`_.
- Subtracting a scalar ``cftime.datetime`` object from a
:py:class:`CFTimeIndex` now results in a :py:class:`pandas.TimedeltaIndex`
instead of raising a ``TypeError`` (:issue:`2671`). By `Spencer Clark
<https://github.com/spencerkclark>`_.

.. _whats-new.0.11.2:

Expand Down
6 changes: 5 additions & 1 deletion xarray/coding/cftimeindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,13 +411,17 @@ def __radd__(self, other):
return CFTimeIndex(other + np.array(self))

def __sub__(self, other):
if isinstance(other, CFTimeIndex):
import cftime
if isinstance(other, (CFTimeIndex, cftime.datetime)):
return pd.TimedeltaIndex(np.array(self) - np.array(other))
elif isinstance(other, pd.TimedeltaIndex):
return CFTimeIndex(np.array(self) - other.to_pytimedelta())
else:
return CFTimeIndex(np.array(self) - other)

def __rsub__(self, other):
return pd.TimedeltaIndex(other - np.array(self))

def _add_delta(self, deltas):
# To support TimedeltaIndex + CFTimeIndex with older versions of
# pandas. No longer used as of pandas 0.23.
Expand Down
20 changes: 20 additions & 0 deletions xarray/tests/test_cftimeindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,26 @@ def test_cftimeindex_sub_cftimeindex(calendar):
assert isinstance(result, pd.TimedeltaIndex)


@pytest.mark.skipif(not has_cftime, reason='cftime not installed')
@pytest.mark.parametrize('calendar', _CFTIME_CALENDARS)
def test_cftimeindex_sub_cftime_datetime(calendar):
a = xr.cftime_range('2000', periods=5, calendar=calendar)
result = a - a[0]
expected = pd.TimedeltaIndex([timedelta(days=i) for i in range(5)])
assert result.equals(expected)
assert isinstance(result, pd.TimedeltaIndex)


@pytest.mark.skipif(not has_cftime, reason='cftime not installed')
@pytest.mark.parametrize('calendar', _CFTIME_CALENDARS)
def test_cftime_datetime_sub_cftimeindex(calendar):
a = xr.cftime_range('2000', periods=5, calendar=calendar)
result = a[0] - a
expected = pd.TimedeltaIndex([timedelta(days=-i) for i in range(5)])
assert result.equals(expected)
assert isinstance(result, pd.TimedeltaIndex)


@pytest.mark.skipif(not has_cftime, reason='cftime not installed')
@pytest.mark.parametrize('calendar', _CFTIME_CALENDARS)
def test_cftimeindex_sub_timedeltaindex(calendar):
Expand Down