Skip to content

Commit 0c4f165

Browse files
authored
FIX: handle NaT values in dt-accessor (#8084)
* FIX: handle NaT values in dt-accessor * FIX: only use isnat-check for datetimes not cftime * check for <NA> and apply needed dtype for isocalendar * Keep current version without NaT * add whats-new.rst entry
1 parent 218ea21 commit 0c4f165

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

doc/whats-new.rst

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ Bug fixes
6666
- Fix bug where :py:class:`DataArray` instances on the right-hand side
6767
of :py:meth:`DataArray.__setitem__` lose dimension names.
6868
(:issue:`7030`, :pull:`8067`) By `Darsh Ranjan <https://github.com/dranjan>`_.
69+
- Return ``float64`` in presence of ``NaT`` in :py:class:`~core.accessor_dt.DatetimeAccessor` and
70+
special case ``NaT`` handling in :py:meth:`~core.accessor_dt.DatetimeAccessor.isocalendar()`
71+
(:issue:`7928`, :pull:`8084`).
72+
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.
6973

7074
Documentation
7175
~~~~~~~~~~~~~

xarray/core/accessor_dt.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,25 @@ def _access_through_series(values, name):
7474
months = values_as_series.dt.month.values
7575
field_values = _season_from_months(months)
7676
elif name == "isocalendar":
77+
# special NaT-handling can be removed when
78+
# https://github.com/pandas-dev/pandas/issues/54657 is resolved
79+
field_values = values_as_series.dt.isocalendar()
80+
# test for <NA> and apply needed dtype
81+
hasna = any(field_values.year.isnull())
82+
if hasna:
83+
field_values = np.dstack(
84+
[
85+
getattr(field_values, name).astype(np.float64, copy=False).values
86+
for name in ["year", "week", "day"]
87+
]
88+
)
89+
else:
90+
field_values = np.array(field_values, dtype=np.int64)
7791
# isocalendar returns iso- year, week, and weekday -> reshape
78-
field_values = np.array(values_as_series.dt.isocalendar(), dtype=np.int64)
7992
return field_values.T.reshape(3, *values.shape)
8093
else:
8194
field_values = getattr(values_as_series.dt, name).values
95+
8296
return field_values.reshape(values.shape)
8397

8498

@@ -110,7 +124,7 @@ def _get_date_field(values, name, dtype):
110124
from dask.array import map_blocks
111125

112126
new_axis = chunks = None
113-
# isocalendar adds adds an axis
127+
# isocalendar adds an axis
114128
if name == "isocalendar":
115129
chunks = (3,) + values.chunksize
116130
new_axis = 0
@@ -119,7 +133,12 @@ def _get_date_field(values, name, dtype):
119133
access_method, values, name, dtype=dtype, new_axis=new_axis, chunks=chunks
120134
)
121135
else:
122-
return access_method(values, name).astype(dtype, copy=False)
136+
out = access_method(values, name)
137+
# cast only for integer types to keep float64 in presence of NaT
138+
# see https://github.com/pydata/xarray/issues/7928
139+
if np.issubdtype(out.dtype, np.integer):
140+
out = out.astype(dtype, copy=False)
141+
return out
123142

124143

125144
def _round_through_series_or_index(values, name, freq):

0 commit comments

Comments
 (0)