Skip to content

Commit 4b18065

Browse files
Ensure datetime-like variables are left unmodified by decode_cf_variable (#6489)
* Add fix to decode_cf_variable * Add PR link to what's new * Variable.data is not lazy so only attempt it on object type arrays * Add a check that the decoded variable is identical to the input
1 parent 5f01c11 commit 4b18065

File tree

4 files changed

+37
-2
lines changed

4 files changed

+37
-2
lines changed

doc/whats-new.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ Bug fixes
8383
- Allow passing both ``other`` and ``drop=True`` arguments to ``xr.DataArray.where``
8484
and ``xr.Dataset.where`` (:pull:`6466`, :pull:`6467`).
8585
By `Michael Delgado <https://github.com/delgadom>`_.
86+
- Ensure dtype encoding attributes are not added or modified on variables that
87+
contain datetime-like values prior to being passed to
88+
:py:func:`xarray.conventions.decode_cf_variable` (:issue:`6453`,
89+
:pull:`6489`). By `Spencer Clark <https://github.com/spencerkclark>`_.
8690

8791
Documentation
8892
~~~~~~~~~~~~~

xarray/conventions.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from .coding import strings, times, variables
88
from .coding.variables import SerializationWarning, pop_to
99
from .core import duck_array_ops, indexing
10-
from .core.common import contains_cftime_datetimes
10+
from .core.common import _contains_datetime_like_objects, contains_cftime_datetimes
1111
from .core.pycompat import is_duck_dask_array
1212
from .core.variable import IndexVariable, Variable, as_variable
1313

@@ -340,6 +340,11 @@ def decode_cf_variable(
340340
A variable holding the decoded equivalent of var.
341341
"""
342342
var = as_variable(var)
343+
344+
# Ensure datetime-like Variables are passed through unmodified (GH 6453)
345+
if _contains_datetime_like_objects(var):
346+
return var
347+
343348
original_dtype = var.dtype
344349

345350
if decode_timedelta is None:

xarray/core/common.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1862,7 +1862,10 @@ def _contains_cftime_datetimes(array) -> bool:
18621862

18631863
def contains_cftime_datetimes(var) -> bool:
18641864
"""Check if an xarray.Variable contains cftime.datetime objects"""
1865-
return _contains_cftime_datetimes(var.data)
1865+
if var.dtype == np.dtype("O") and var.size > 0:
1866+
return _contains_cftime_datetimes(var.data)
1867+
else:
1868+
return False
18661869

18671870

18681871
def _contains_datetime_like_objects(var) -> bool:

xarray/tests/test_conventions.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
Dataset,
1010
SerializationWarning,
1111
Variable,
12+
cftime_range,
1213
coding,
1314
conventions,
1415
open_dataset,
@@ -442,3 +443,25 @@ def test_decode_cf_variable_with_array_units(self) -> None:
442443
v = Variable(["t"], [1, 2, 3], {"units": np.array(["foobar"], dtype=object)})
443444
v_decoded = conventions.decode_cf_variable("test2", v)
444445
assert_identical(v, v_decoded)
446+
447+
448+
def test_decode_cf_variable_timedelta64():
449+
variable = Variable(["time"], pd.timedelta_range("1D", periods=2))
450+
decoded = conventions.decode_cf_variable("time", variable)
451+
assert decoded.encoding == {}
452+
assert_identical(decoded, variable)
453+
454+
455+
def test_decode_cf_variable_datetime64():
456+
variable = Variable(["time"], pd.date_range("2000", periods=2))
457+
decoded = conventions.decode_cf_variable("time", variable)
458+
assert decoded.encoding == {}
459+
assert_identical(decoded, variable)
460+
461+
462+
@requires_cftime
463+
def test_decode_cf_variable_cftime():
464+
variable = Variable(["time"], cftime_range("2000", periods=2))
465+
decoded = conventions.decode_cf_variable("time", variable)
466+
assert decoded.encoding == {}
467+
assert_identical(decoded, variable)

0 commit comments

Comments
 (0)