From 4a0808ff990d8156174135303be9463acd1ba1f6 Mon Sep 17 00:00:00 2001 From: Spencer Clark Date: Sat, 24 Feb 2024 10:32:05 -0500 Subject: [PATCH] Fix non-nanosecond casting behavior for expand_dims --- doc/whats-new.rst | 5 +++++ xarray/core/variable.py | 10 ++++++---- xarray/tests/test_dataset.py | 8 ++++++++ xarray/tests/test_variable.py | 16 ++++++++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 9d7eb55071b..ee3935325d5 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -40,6 +40,11 @@ Bug fixes - The default ``freq`` parameter in :py:meth:`xr.date_range` and :py:meth:`xr.cftime_range` is set to ``'D'`` only if ``periods``, ``start``, or ``end`` are ``None`` (:issue:`8770`, :pull:`8774`). By `Roberto Chang `_. +- Ensure that non-nanosecond precision :py:class:`numpy.datetime64` and + :py:class:`numpy.timedelta64` values are cast to nanosecond precision values + when used in :py:meth:`DataArray.expand_dims` and + ::py:meth:`Dataset.expand_dims` (:pull:`8781`). By `Spencer + Clark `_. Documentation ~~~~~~~~~~~~~ diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 6834931fa11..f071afe4e07 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -218,10 +218,12 @@ def _possibly_convert_datetime_or_timedelta_index(data): this in version 2.0.0, in xarray we will need to make sure we are ready to handle non-nanosecond precision datetimes or timedeltas in our code before allowing such values to pass through unchanged.""" - if isinstance(data, (pd.DatetimeIndex, pd.TimedeltaIndex)): - return _as_nanosecond_precision(data) - else: - return data + if isinstance(data, PandasIndexingAdapter): + if isinstance(data.array, (pd.DatetimeIndex, pd.TimedeltaIndex)): + data = PandasIndexingAdapter(_as_nanosecond_precision(data.array)) + elif isinstance(data, (pd.DatetimeIndex, pd.TimedeltaIndex)): + data = _as_nanosecond_precision(data) + return data def as_compatible_data( diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 5dcd4e0fe98..4937fc5f3a3 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -60,6 +60,7 @@ requires_cupy, requires_dask, requires_numexpr, + requires_pandas_version_two, requires_pint, requires_scipy, requires_sparse, @@ -3446,6 +3447,13 @@ def test_expand_dims_kwargs_python36plus(self) -> None: ) assert_identical(other_way_expected, other_way) + @requires_pandas_version_two + def test_expand_dims_non_nanosecond_conversion(self) -> None: + # Regression test for https://github.com/pydata/xarray/issues/7493#issuecomment-1953091000 + with pytest.warns(UserWarning, match="non-nanosecond precision"): + ds = Dataset().expand_dims({"time": [np.datetime64("2018-01-01", "s")]}) + assert ds.time.dtype == np.dtype("datetime64[ns]") + def test_set_index(self) -> None: expected = create_test_multiindex() mindex = expected["x"].to_index() diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index 6575f2e1740..73f5abe66e5 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -3011,3 +3011,19 @@ def test_pandas_two_only_timedelta_conversion_warning() -> None: var = Variable(["time"], data) assert var.dtype == np.dtype("timedelta64[ns]") + + +@requires_pandas_version_two +@pytest.mark.parametrize( + ("index", "dtype"), + [ + (pd.date_range("2000", periods=1), "datetime64"), + (pd.timedelta_range("1", periods=1), "timedelta64"), + ], + ids=lambda x: f"{x}", +) +def test_pandas_indexing_adapter_non_nanosecond_conversion(index, dtype) -> None: + data = PandasIndexingAdapter(index.astype(f"{dtype}[s]")) + with pytest.warns(UserWarning, match="non-nanosecond precision"): + var = Variable(["time"], data) + assert var.dtype == np.dtype(f"{dtype}[ns]")