Skip to content

Commit 5761de6

Browse files
authored
fix upstream dev issues (pydata#9953)
* fix pandas dev issues * add whats-new.rst entry
1 parent 6bea715 commit 5761de6

File tree

3 files changed

+43
-14
lines changed

3 files changed

+43
-14
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ Deprecations
6363

6464
Bug fixes
6565
~~~~~~~~~
66+
- Fix issues related to Pandas v3 ("us" vs. "ns" for python datetime, copy on write) and handling of 0d-numpy arrays in datetime/timedelta decoding (:pull:`9953`).
67+
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.
6668

6769

6870
Documentation

xarray/coding/times.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -579,20 +579,23 @@ def _numbers_to_timedelta(
579579
) -> np.ndarray:
580580
"""Transform numbers to np.timedelta64."""
581581
# keep NaT/nan mask
582-
nan = np.isnan(flat_num) | (flat_num == np.iinfo(np.int64).min)
582+
if flat_num.dtype.kind == "f":
583+
nan = np.asarray(np.isnan(flat_num))
584+
elif flat_num.dtype.kind == "i":
585+
nan = np.asarray(flat_num == np.iinfo(np.int64).min)
583586

584587
# in case we need to change the unit, we fix the numbers here
585588
# this should be safe, as errors would have been raised above
586589
ns_time_unit = _NS_PER_TIME_DELTA[time_unit]
587590
ns_ref_date_unit = _NS_PER_TIME_DELTA[ref_unit]
588591
if ns_time_unit > ns_ref_date_unit:
589-
flat_num *= np.int64(ns_time_unit / ns_ref_date_unit)
592+
flat_num = np.asarray(flat_num * np.int64(ns_time_unit / ns_ref_date_unit))
590593
time_unit = ref_unit
591594

592595
# estimate fitting resolution for floating point values
593596
# this iterates until all floats are fractionless or time_unit == "ns"
594597
if flat_num.dtype.kind == "f" and time_unit != "ns":
595-
flat_num_dates, new_time_unit = _check_higher_resolution(flat_num, time_unit) # type: ignore[arg-type]
598+
flat_num, new_time_unit = _check_higher_resolution(flat_num, time_unit)
596599
if time_unit != new_time_unit:
597600
msg = (
598601
f"Can't decode floating point {datatype} to {time_unit!r} without "
@@ -608,7 +611,8 @@ def _numbers_to_timedelta(
608611
with warnings.catch_warnings():
609612
warnings.simplefilter("ignore", RuntimeWarning)
610613
flat_num = flat_num.astype(np.int64)
611-
flat_num[nan] = np.iinfo(np.int64).min
614+
if nan.any():
615+
flat_num[nan] = np.iinfo(np.int64).min
612616

613617
# cast to wanted type
614618
return flat_num.astype(f"timedelta64[{time_unit}]")

xarray/tests/test_variable.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
assert_identical,
3838
assert_no_warnings,
3939
has_dask_ge_2024_11_0,
40+
has_pandas_3,
4041
raise_if_dask_computes,
4142
requires_bottleneck,
4243
requires_cupy,
@@ -208,8 +209,11 @@ def test_index_0d_datetime(self):
208209
x = self.cls(["x"], [np.datetime64(d)])
209210
self._assertIndexedLikeNDArray(x, np.datetime64(d), "datetime64[us]")
210211

212+
expected_unit = "us" if has_pandas_3 else "ns"
211213
x = self.cls(["x"], pd.DatetimeIndex([d]))
212-
self._assertIndexedLikeNDArray(x, np.datetime64(d), "datetime64[ns]")
214+
self._assertIndexedLikeNDArray(
215+
x, np.datetime64(d), f"datetime64[{expected_unit}]"
216+
)
213217

214218
def test_index_0d_timedelta64(self):
215219
td = timedelta(hours=1)
@@ -283,7 +287,10 @@ def test_0d_time_data(self):
283287
(dt64_data.values.astype("datetime64[m]"), "s"),
284288
(dt64_data.values.astype("datetime64[s]"), "s"),
285289
(dt64_data.values.astype("datetime64[ps]"), "ns"),
286-
(dt64_data.to_pydatetime(), "ns"),
290+
(
291+
dt64_data.to_pydatetime(),
292+
"us" if has_pandas_3 else "ns",
293+
),
287294
],
288295
)
289296
def test_datetime64_conversion(self, values, unit):
@@ -1071,8 +1078,14 @@ def test_numpy_same_methods(self):
10711078
"values, unit",
10721079
[
10731080
(np.datetime64("2000-01-01"), "s"),
1074-
(pd.Timestamp("2000-01-01T00"), "ns"),
1075-
(datetime(2000, 1, 1), "ns"),
1081+
(
1082+
pd.Timestamp("2000-01-01T00"),
1083+
"s" if has_pandas_3 else "ns",
1084+
),
1085+
(
1086+
datetime(2000, 1, 1),
1087+
"us" if has_pandas_3 else "ns",
1088+
),
10761089
(np.datetime64("2000-01-01T00:00:00.1234567891"), "ns"),
10771090
],
10781091
)
@@ -1109,8 +1122,9 @@ def test_0d_str(self):
11091122

11101123
def test_0d_datetime(self):
11111124
v = Variable([], pd.Timestamp("2000-01-01"))
1112-
assert v.dtype == np.dtype("datetime64[ns]")
1113-
assert v.values == np.datetime64("2000-01-01", "ns")
1125+
expected_unit = "s" if has_pandas_3 else "ns"
1126+
assert v.dtype == np.dtype(f"datetime64[{expected_unit}]")
1127+
assert v.values == np.datetime64("2000-01-01", expected_unit)
11141128

11151129
@pytest.mark.parametrize(
11161130
"values, unit", [(pd.to_timedelta("1s"), "ns"), (np.timedelta64(1, "s"), "s")]
@@ -2654,11 +2668,14 @@ def test_datetime(self):
26542668
assert np.dtype("datetime64[ns]") == actual.dtype
26552669
assert expected is source_ndarray(np.asarray(actual))
26562670

2657-
expected = np.datetime64("2000-01-01", "ns")
2671+
expected = np.datetime64(
2672+
"2000-01-01",
2673+
"us" if has_pandas_3 else "ns",
2674+
)
26582675
actual = as_compatible_data(datetime(2000, 1, 1))
26592676
assert np.asarray(expected) == actual
26602677
assert np.ndarray is type(actual)
2661-
assert np.dtype("datetime64[ns]") == actual.dtype
2678+
assert expected.dtype == actual.dtype
26622679

26632680
def test_tz_datetime(self) -> None:
26642681
tz = pytz.timezone("America/New_York")
@@ -2980,8 +2997,14 @@ def test_from_pint_wrapping_dask(self, Var):
29802997
(np.array([np.datetime64("2000-01-01", "ns")]), "ns"),
29812998
(np.array([np.datetime64("2000-01-01", "s")]), "s"),
29822999
(pd.date_range("2000", periods=1), "ns"),
2983-
(datetime(2000, 1, 1), "ns"),
2984-
(np.array([datetime(2000, 1, 1)]), "ns"),
3000+
(
3001+
datetime(2000, 1, 1),
3002+
"us" if has_pandas_3 else "ns",
3003+
),
3004+
(
3005+
np.array([datetime(2000, 1, 1)]),
3006+
"us" if has_pandas_3 else "ns",
3007+
),
29853008
(pd.date_range("2000", periods=1, tz=pytz.timezone("America/New_York")), "ns"),
29863009
(
29873010
pd.Series(

0 commit comments

Comments
 (0)