Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ Bug Fixes
entries; ``to_dataframe`` indexes by the union of stored entries across all
sparse variables sharing the same dims (:issue:`4007`).
By `patnr <https://github.com/patnr>`_.
- Following `pandas-dev/pandas#64793`_, ensure that resampling an array to a
``Day`` frequency along a :py:class:`xarray.CFTimeIndex` produces the same
results as resampling to an equivalent ``Hour`` frequency, including with the
use of ``origin`` and ``offset`` options (:pull:`11546`). This effectively
rolls back the resample-related changes introduced in :pull:`10650`. By
`Spencer Clark <https://github.com/spencerkclark>`_.

.. _`pandas-dev/pandas#64793`: https://github.com/pandas-dev/pandas/pull/64793

Documentation
~~~~~~~~~~~~~
Expand Down
17 changes: 10 additions & 7 deletions xarray/core/resample_cftime.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@
import pandas as pd

from xarray.coding.cftime_offsets import (
CFTIME_TICKS,
BaseCFTimeOffset,
Day,
Hour,
MonthEnd,
QuarterEnd,
Tick,
Expand Down Expand Up @@ -86,19 +87,19 @@ def __init__(
self.freq = to_offset(freq)
self.origin = origin

if not isinstance(self.freq, CFTIME_TICKS):
if not isinstance(self.freq, (Tick, Day)):
if offset is not None:
message = (
"The 'offset' keyword does not take effect when "
"resampling with a 'freq' that is not Tick-like (h, m, s, "
"ms, us)"
"resampling with a 'freq' that is not Tick-like (D, h, m, "
"s, ms, us)"
)
emit_user_level_warning(message, category=RuntimeWarning)
if origin != "start_day":
message = (
"The 'origin' keyword does not take effect when "
"resampling with a 'freq' that is not Tick-like (h, m, s, "
"ms, us)"
"resampling with a 'freq' that is not Tick-like (D, h, m, "
"s, ms, us)"
)
emit_user_level_warning(message, category=RuntimeWarning)

Expand Down Expand Up @@ -338,7 +339,9 @@ def _get_range_edges(
last : cftime.datetime
Corrected ending datetime object for resampled CFTimeIndex range.
"""
if isinstance(freq, Tick):
if isinstance(freq, (Tick, Day)):
if isinstance(freq, Day):
freq = Hour(24 * freq.n)
first, last = _adjust_dates_anchored(
first, last, freq, closed=closed, origin=origin, offset=offset
)
Expand Down
2 changes: 1 addition & 1 deletion xarray/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def get_dask_chunkmanager():
has_flox, requires_flox = _importorskip("flox")
has_netcdf, requires_netcdf = _importorskip("netcdf")
has_pandas_3, requires_pandas_3 = _importorskip("pandas", "3.0.0")

has_pandas_3_1, requires_pandas_3_1 = _importorskip("pandas", "3.1.0.dev0")

# some special cases
has_scipy_or_netCDF4 = has_scipy or has_netCDF4
Expand Down
16 changes: 9 additions & 7 deletions xarray/tests/test_cftimeindex_resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@

import xarray as xr
from xarray.coding.cftime_offsets import (
CFTIME_TICKS,
Day,
Tick,
to_offset,
)
from xarray.coding.cftimeindex import CFTimeIndex
from xarray.core.resample_cftime import CFTimeGrouper
from xarray.core.types import PDDatetimeUnitOptions
from xarray.tests import has_pandas_3
from xarray.tests import has_pandas_3_1

cftime = pytest.importorskip("cftime")

Expand Down Expand Up @@ -60,9 +60,11 @@


def has_tick_resample_freq(freqs):
resample_freq, _ = freqs
_, resample_freq = freqs

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This was previously inadvertently filtering on the initial_freq rather than the resample_freq...

By coincidence that happened to be OK given the set of frequency pairs that we were filtering and the pandas behavior at the time, but that is not the case anymore. This fixes that bug.

resample_freq_as_offset = to_offset(resample_freq)
return isinstance(resample_freq_as_offset, CFTIME_TICKS)
# As of pandas 3.1, in the context of resampling a timezone-naive index,
# Day is treated like a Tick frequency (pandas-dev/pandas#64793).
return isinstance(resample_freq_as_offset, (Tick, Day))


def has_non_tick_resample_freq(freqs):
Expand Down Expand Up @@ -137,6 +139,9 @@ def da(index) -> xr.DataArray:
@pytest.mark.parametrize("offset", [None, "5s"], ids=lambda x: f"{x}")
def test_resample_with_tick_resample_freq(freqs, closed, label, offset) -> None:
initial_freq, resample_freq = freqs
resample_freq_as_offset = to_offset(resample_freq)
if isinstance(resample_freq_as_offset, Day) and not has_pandas_3_1:
pytest.skip("Only valid for pandas >= 3.1")
start = "2000-01-01T12:07:01"
origin = "start"

Expand Down Expand Up @@ -165,9 +170,6 @@ def test_resample_with_tick_resample_freq(freqs, closed, label, offset) -> None:
@pytest.mark.parametrize("label", [None, "left", "right"])
def test_resample_with_non_tick_resample_freq(freqs, closed, label) -> None:
initial_freq, resample_freq = freqs
resample_freq_as_offset = to_offset(resample_freq)
if isinstance(resample_freq_as_offset, Day) and not has_pandas_3:
pytest.skip("Only valid for pandas >= 3.0")
start = "2000-01-01T12:07:01"

# Set offset and origin to their default values since they have no effect
Expand Down
Loading