Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix datetime encoding precision loss regression for units requiring floating point values #8272

Merged
merged 1 commit into from Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/whats-new.rst
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
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
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