Skip to content
Open
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
25 changes: 23 additions & 2 deletions xarray/backends/zarr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1090,8 +1090,29 @@ def store(
)
vars_with_encoding[vn] = variables[vn].copy(deep=False)
vars_with_encoding[vn].encoding = existing_vars[vn].encoding
vars_with_encoding, _ = self.encode(vars_with_encoding, {})
variables_encoded.update(vars_with_encoding)

# Skip CF encoding for zarr v3 native DateTime64 arrays (GH#11350).
native_datetime_vars: set[str] = set()
if _zarr_v3() and self.zarr_group.metadata.zarr_format == 3:
from zarr.dtype import DateTime64

for vn in existing_variable_names:
name = _encode_variable_name(vn)
zarr_array = self.members[name]
if isinstance(zarr_array.metadata.data_type, DateTime64):
native_datetime_vars.add(vn)

vars_to_encode = {
vn: v
for vn, v in vars_with_encoding.items()
if vn not in native_datetime_vars
}
if vars_to_encode:
encoded, _ = self.encode(vars_to_encode, {})
variables_encoded.update(encoded)

for vn in native_datetime_vars:
variables_encoded[vn] = vars_with_encoding[vn]

for var_name in existing_variable_names:
variables_encoded[var_name] = _validate_and_transpose_existing_dims(
Expand Down
29 changes: 29 additions & 0 deletions xarray/tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -8153,3 +8153,32 @@ def test_get_mtime_non_file_paths() -> None:

# GDAL virtual filesystem paths are not real files
assert _get_mtime("/vsicurl/https://example.com/file.nc") is None


@requires_zarr
@requires_zarr_v3
def test_zarr_datetime64_roundtrip_no_corruption() -> None:
"""Regression test for https://github.com/pydata/xarray/issues/11350.

Writing a dataset back to a zarr store with native DateTime64 dtype
should not corrupt the datetime values.
"""
import zarr.dtype

store = zarr.storage.MemoryStore()
g = zarr.create_group(store)
a = g.create_array(
"a",
shape=(2,),
dtype=zarr.dtype.DateTime64(unit="s", scale_factor=1),
dimension_names=["time"],
)
a[:] = np.array(["2025-01-01", "2025-01-02"], dtype="<M8[us]")

ds = xr.open_zarr(store, chunks=None, consolidated=False).compute()
expected = ds["a"].values.copy()

ds.to_zarr(store, mode="r+", consolidated=False)

ds_roundtripped = xr.open_zarr(store, chunks=None, consolidated=False).compute()
np.testing.assert_array_equal(ds_roundtripped["a"].values, expected)
Loading