Skip to content

Commit 4b3d74a

Browse files
committed
reverse order of DatetimeCoder and MaskCoder in encoding/decoding, retrieve wanted fill_value in MaskCoder
1 parent 3d428f7 commit 4b3d74a

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

xarray/coding/variables.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import numpy as np
1010
import pandas as pd
1111

12+
from xarray.coding import times
1213
from xarray.core import dtypes, duck_array_ops, indexing
1314
from xarray.core.pycompat import is_duck_dask_array
1415
from xarray.core.variable import Variable
@@ -239,6 +240,16 @@ def encode(self, variable: Variable, name: T_Name = None):
239240
# Ensure _FillValue is cast to same dtype as data's
240241
encoding["_FillValue"] = dtype.type(fv)
241242
fill_value = pop_to(encoding, attrs, "_FillValue", name=name)
243+
# retrieve _FillValue in case of np.datetime64
244+
# see GH 7817
245+
if np.issubdtype(data.dtype, np.datetime64):
246+
units = encoding.get("units", None)
247+
if isinstance(units, str) and "since" in units:
248+
delta, _ = times._unpack_netcdf_time_units(units)
249+
delta = times._netcdf_to_numpy_timeunit(delta)
250+
fill_value = np.datetime64(fill_value.item(), delta).astype(
251+
"datetime64[ns]"
252+
)
242253
if not pd.isnull(fill_value):
243254
data = duck_array_ops.fillna(data, fill_value)
244255

@@ -275,7 +286,17 @@ def decode(self, variable: Variable, name: T_Name = None):
275286
)
276287

277288
dtype, decoded_fill_value = dtypes.maybe_promote(data.dtype)
278-
289+
# retrieve _FillValue in case of np.datetime64
290+
# see GH 7817
291+
if np.issubdtype(data.dtype, np.datetime64) and decoded_fill_value.astype(
292+
np.int64
293+
) == np.datetime64("NaT").astype(np.int64):
294+
delta, _ = times._unpack_netcdf_time_units(encoding["units"])
295+
delta = times._netcdf_to_numpy_timeunit(delta)
296+
encoded_fill_values = {
297+
np.datetime64(encfill.item(), delta).astype("datetime64[ns]")
298+
for encfill in encoded_fill_values
299+
}
279300
if encoded_fill_values:
280301
transform = partial(
281302
_apply_mask,

xarray/conventions.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,10 @@ def encode_cf_variable(
174174
ensure_not_multiindex(var, name=name)
175175

176176
for coder in [
177-
times.CFDatetimeCoder(),
178-
times.CFTimedeltaCoder(),
179177
variables.CFScaleOffsetCoder(),
180178
variables.CFMaskCoder(),
179+
times.CFDatetimeCoder(),
180+
times.CFTimedeltaCoder(),
181181
variables.UnsignedIntegerCoder(),
182182
variables.NonStringCoder(),
183183
variables.DefaultFillvalueCoder(),
@@ -263,6 +263,13 @@ def decode_cf_variable(
263263
var = strings.CharacterArrayCoder().decode(var, name=name)
264264
var = strings.EncodedStringCoder().decode(var)
265265

266+
# time decoding before masking
267+
# GH 7817
268+
if decode_timedelta:
269+
var = times.CFTimedeltaCoder().decode(var, name=name)
270+
if decode_times:
271+
var = times.CFDatetimeCoder(use_cftime=use_cftime).decode(var, name=name)
272+
266273
if mask_and_scale:
267274
for coder in [
268275
variables.UnsignedIntegerCoder(),
@@ -271,11 +278,6 @@ def decode_cf_variable(
271278
]:
272279
var = coder.decode(var, name=name)
273280

274-
if decode_timedelta:
275-
var = times.CFTimedeltaCoder().decode(var, name=name)
276-
if decode_times:
277-
var = times.CFDatetimeCoder(use_cftime=use_cftime).decode(var, name=name)
278-
279281
if decode_endianness and not var.dtype.isnative:
280282
var = variables.EndianCoder().decode(var)
281283
original_dtype = var.dtype

0 commit comments

Comments
 (0)