Skip to content

Commit 60f72ef

Browse files
authored
Attempt datetime coding using cftime when pandas fails (#6049)
* Add tests for valid cf times / invalid pandas times * Attempt datetime coding using cftime when pandas fails * Add a line to whats-new.rst * Add @requires_cftime test decorator
1 parent ddc500a commit 60f72ef

File tree

4 files changed

+28
-3
lines changed

4 files changed

+28
-3
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ Bug fixes
7979
By `Sebastian Weigand <https://github.com/s-weigand>`_.
8080
- Fix a regression in the removal of duplicate backend entrypoints (:issue:`5944`, :pull:`5959`)
8181
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.
82+
- Fix an issue that datasets from being saved when time variables with units that ``cftime`` can parse but pandas can not were present (:pull:`6049`).
83+
By `Tim Heap <https://github.com/mx-moth>`_.
8284

8385
Documentation
8486
~~~~~~~~~~~~~

xarray/coding/times.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,9 @@ def _cleanup_netcdf_time_units(units):
400400
delta, ref_date = _unpack_netcdf_time_units(units)
401401
try:
402402
units = "{} since {}".format(delta, format_timestamp(ref_date))
403-
except OutOfBoundsDatetime:
404-
# don't worry about reifying the units if they're out of bounds
403+
except (OutOfBoundsDatetime, ValueError):
404+
# don't worry about reifying the units if they're out of bounds or
405+
# formatted badly
405406
pass
406407
return units
407408

@@ -482,7 +483,7 @@ def encode_cf_datetime(dates, units=None, calendar=None):
482483
num = time_deltas / time_delta
483484
num = num.values.reshape(dates.shape)
484485

485-
except (OutOfBoundsDatetime, OverflowError):
486+
except (OutOfBoundsDatetime, OverflowError, ValueError):
486487
num = _encode_datetime_with_cftime(dates, units, calendar)
487488

488489
num = cast_to_int_if_safe(num)

xarray/tests/test_coding_times.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,23 @@ def test_encode_cf_datetime_pandas_min() -> None:
853853
assert calendar == expected_calendar
854854

855855

856+
@requires_cftime
857+
def test_encode_cf_datetime_invalid_pandas_valid_cftime() -> None:
858+
num, units, calendar = encode_cf_datetime(
859+
pd.date_range("2000", periods=3),
860+
# Pandas fails to parse this unit, but cftime is quite happy with it
861+
"days since 1970-01-01 00:00:00 00",
862+
"standard",
863+
)
864+
865+
expected_num = [10957, 10958, 10959]
866+
expected_units = "days since 1970-01-01 00:00:00 00"
867+
expected_calendar = "standard"
868+
assert_array_equal(num, expected_num)
869+
assert units == expected_units
870+
assert calendar == expected_calendar
871+
872+
856873
@requires_cftime
857874
def test_time_units_with_timezone_roundtrip(calendar) -> None:
858875
# Regression test for GH 2649

xarray/tests/test_formatting.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ def test_pretty_print(self) -> None:
188188
def test_maybe_truncate(self) -> None:
189189
assert formatting.maybe_truncate("ß", 10) == "ß"
190190

191+
def test_format_timestamp_invalid_pandas_format(self) -> None:
192+
expected = "2021-12-06 17:00:00 00"
193+
with pytest.raises(ValueError):
194+
formatting.format_timestamp(expected)
195+
191196
def test_format_timestamp_out_of_bounds(self) -> None:
192197
from datetime import datetime
193198

0 commit comments

Comments
 (0)