Skip to content

Commit

Permalink
Fix time encoding regression
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerkclark committed Oct 4, 2023
1 parent d5f1785 commit 8f271a3
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 4 deletions.
6 changes: 6 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ Deprecations
Bug fixes
~~~~~~~~~

- Fix datetime encoding precision loss regression introduced in the previous
release for datetimes encoded with units requiring floating point values, and
a reference date not equal to the first value of the datetime array
(:issue:`8271`, :pull:`8272`). By `Spencer Clark
<https://github.com/spencerkclark>`_.


Documentation
~~~~~~~~~~~~~
Expand Down
3 changes: 2 additions & 1 deletion xarray/coding/times.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,8 @@ def encode_cf_datetime(
if data_units != units:
# this accounts for differences in the reference times
ref_delta = abs(data_ref_date - ref_date).to_timedelta64()
if ref_delta > np.timedelta64(0, "ns"):
data_delta = _time_units_to_timedelta64(needed_units)
if (ref_delta % data_delta) > np.timedelta64(0, "ns"):
needed_units = _infer_time_units_from_diff(ref_delta)

# needed time delta to encode faithfully to int64
Expand Down
11 changes: 8 additions & 3 deletions xarray/tests/test_coding_times.py
Original file line number Diff line number Diff line change
Expand Up @@ -1363,18 +1363,23 @@ def test_roundtrip_timedelta64_nanosecond_precision_warning() -> None:


def test_roundtrip_float_times() -> None:
# Regression test for GitHub issue #8271
fill_value = 20.0
times = [np.datetime64("2000-01-01 12:00:00", "ns"), np.datetime64("NaT", "ns")]
times = [
np.datetime64("1970-01-01 00:00:00", "ns"),
np.datetime64("1970-01-01 06:00:00", "ns"),
np.datetime64("NaT", "ns"),
]

units = "days since 2000-01-01"
units = "days since 1960-01-01"
var = Variable(
["time"],
times,
encoding=dict(dtype=np.float64, _FillValue=fill_value, units=units),
)

encoded_var = conventions.encode_cf_variable(var)
np.testing.assert_array_equal(encoded_var, np.array([0.5, 20.0]))
np.testing.assert_array_equal(encoded_var, np.array([3653, 3653.25, 20.0]))
assert encoded_var.attrs["units"] == units
assert encoded_var.attrs["_FillValue"] == fill_value

Expand Down

0 comments on commit 8f271a3

Please sign in to comment.