Skip to content

Commit ff15a08

Browse files
Fix time indexing regression in convert_calendar (#9192)
* MRC -- Selecting with string for cftime See discussion in #9138 This commit and pull request mostly serves as a staging group for a potential fix. Test with: ``` pytest xarray/tests/test_cftimeindex.py::test_cftime_noleap_with_str ``` * effectively remove fastpath * Add docstring * Revert "effectively remove fastpath" This reverts commit 0f1a5a2. * Fix by reassigning coordinate * Update what's new entry * Simplify if condition --------- Co-authored-by: Spencer Clark <[email protected]>
1 parent eb0fbd7 commit ff15a08

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

doc/whats-new.rst

+6
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ Bug fixes
4747
By `Justus Magin <https://github.com/keewis>`_.
4848
- Promote floating-point numeric datetimes before decoding (:issue:`9179`, :pull:`9182`).
4949
By `Justus Magin <https://github.com/keewis>`_.
50+
- Address regression introduced in :pull:`9002` that prevented objects returned
51+
by py:meth:`DataArray.convert_calendar` to be indexed by a time index in
52+
certain circumstances (:issue:`9138`, :pull:`9192`). By `Mark Harfouche
53+
<https://github.com/hmaarrfk>`_ and `Spencer Clark
54+
<https://github.com/spencerkclark>`.
55+
5056
- Fiy static typing of tolerance arguments by allowing `str` type (:issue:`8892`, :pull:`9194`).
5157
By `Michael Niklas <https://github.com/headtr1ck>`_.
5258
- Dark themes are now properly detected for ``html[data-theme=dark]``-tags (:pull:`9200`).

xarray/coding/calendar_ops.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
from xarray.coding.cftime_offsets import date_range_like, get_date_type
77
from xarray.coding.cftimeindex import CFTimeIndex
8-
from xarray.coding.times import _should_cftime_be_used, convert_times
8+
from xarray.coding.times import (
9+
_should_cftime_be_used,
10+
convert_times,
11+
)
912
from xarray.core.common import _contains_datetime_like_objects, is_np_datetime_like
1013

1114
try:
@@ -222,6 +225,13 @@ def convert_calendar(
222225
# Remove NaN that where put on invalid dates in target calendar
223226
out = out.where(out[dim].notnull(), drop=True)
224227

228+
if use_cftime:
229+
# Reassign times to ensure time index of output is a CFTimeIndex
230+
# (previously it was an Index due to the presence of NaN values).
231+
# Note this is not needed in the case that the output time index is
232+
# a DatetimeIndex, since DatetimeIndexes can handle NaN values.
233+
out[dim] = CFTimeIndex(out[dim].data)
234+
225235
if missing is not None:
226236
time_target = date_range_like(time, calendar=calendar, use_cftime=use_cftime)
227237
out = out.reindex({dim: time_target}, fill_value=missing)

xarray/tests/test_calendar_ops.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from __future__ import annotations
22

33
import numpy as np
4+
import pandas as pd
45
import pytest
56

6-
from xarray import DataArray, infer_freq
7+
from xarray import CFTimeIndex, DataArray, infer_freq
78
from xarray.coding.calendar_ops import convert_calendar, interp_calendar
89
from xarray.coding.cftime_offsets import date_range
910
from xarray.testing import assert_identical
@@ -286,3 +287,25 @@ def test_interp_calendar_errors():
286287
ValueError, match="Both 'source.x' and 'target' must contain datetime objects."
287288
):
288289
interp_calendar(da1, da2, dim="x")
290+
291+
292+
@requires_cftime
293+
@pytest.mark.parametrize(
294+
("source_calendar", "target_calendar", "expected_index"),
295+
[("standard", "noleap", CFTimeIndex), ("all_leap", "standard", pd.DatetimeIndex)],
296+
)
297+
def test_convert_calendar_produces_time_index(
298+
source_calendar, target_calendar, expected_index
299+
):
300+
# https://github.com/pydata/xarray/issues/9138
301+
time = date_range("2000-01-01", "2002-01-01", freq="D", calendar=source_calendar)
302+
temperature = np.ones(len(time))
303+
da = DataArray(
304+
data=temperature,
305+
dims=["time"],
306+
coords=dict(
307+
time=time,
308+
),
309+
)
310+
converted = da.convert_calendar(target_calendar)
311+
assert isinstance(converted.indexes["time"], expected_index)

0 commit comments

Comments
 (0)