diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 471e91a8512..f619284437b 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -96,6 +96,8 @@ Bug fixes :py:meth:`Dataset.to_zarr` (:issue:`4783`, :pull:`4795`). By `Julien Seguinot `_. - Add :py:meth:`Dataset.drop_isel` and :py:meth:`DataArray.drop_isel` (:issue:`4658`, :pull:`4819`). By `Daniel Mesejo `_. +- Fix time encoding bug associated with using cftime versions greater than + 1.4.0 with xarray (:issue:`4870`, :pull:`4871`). By `Spencer Clark `_. Documentation ~~~~~~~~~~~~~ diff --git a/xarray/coding/times.py b/xarray/coding/times.py index 3d877a169f5..67393c45547 100644 --- a/xarray/coding/times.py +++ b/xarray/coding/times.py @@ -391,7 +391,7 @@ def _encode_datetime_with_cftime(dates, units, calendar): def encode_datetime(d): return np.nan if d is None else cftime.date2num(d, units, calendar) - return np.vectorize(encode_datetime)(dates) + return np.array([encode_datetime(d) for d in dates.ravel()]).reshape(dates.shape) def cast_to_int_if_safe(num): diff --git a/xarray/tests/test_coding_times.py b/xarray/tests/test_coding_times.py index dfd558f737e..d8412f82374 100644 --- a/xarray/tests/test_coding_times.py +++ b/xarray/tests/test_coding_times.py @@ -8,6 +8,7 @@ from xarray import DataArray, Dataset, Variable, coding, conventions, decode_cf from xarray.coding.times import ( + _encode_datetime_with_cftime, cftime_to_nptime, decode_cf_datetime, encode_cf_datetime, @@ -995,3 +996,18 @@ def test_encode_decode_roundtrip(freq): encoded = conventions.encode_cf_variable(variable) decoded = conventions.decode_cf_variable("time", encoded) assert_equal(variable, decoded) + + +@requires_cftime +def test__encode_datetime_with_cftime(): + # See GH 4870. cftime versions > 1.4.0 required us to adapt the + # way _encode_datetime_with_cftime was written. + import cftime + + calendar = "gregorian" + times = cftime.num2date([0, 1], "hours since 2000-01-01", calendar) + + encoding_units = "days since 2000-01-01" + expected = cftime.date2num(times, encoding_units, calendar) + result = _encode_datetime_with_cftime(times, encoding_units, calendar) + np.testing.assert_equal(result, expected)