Skip to content

Commit 479d003

Browse files
jbrockmendeljreback
authored andcommitted
BUG: Fix insertion of wrong-dtypes NaT into Series[m8ns] (#27323)
1 parent 957f5e7 commit 479d003

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-2
lines changed

pandas/_libs/index.pyx

+4
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,10 @@ cpdef convert_scalar(ndarray arr, object value):
544544
pass
545545
elif isinstance(value, timedelta):
546546
return Timedelta(value).value
547+
elif util.is_datetime64_object(value):
548+
# exclude np.datetime64("NaT") which would otherwise be picked up
549+
# by the `value != value check below
550+
pass
547551
elif value is None or value != value:
548552
return NPY_NAT
549553
elif isinstance(value, str):

pandas/core/series.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
ABCSparseSeries,
4747
)
4848
from pandas.core.dtypes.missing import (
49+
is_valid_nat_for_dtype,
4950
isna,
5051
na_value_for_dtype,
5152
notna,
@@ -1198,13 +1199,15 @@ def setitem(key, value):
11981199
pass
11991200
elif is_timedelta64_dtype(self.dtype):
12001201
# reassign a null value to iNaT
1201-
if isna(value):
1202+
if is_valid_nat_for_dtype(value, self.dtype):
1203+
# exclude np.datetime64("NaT")
12021204
value = iNaT
12031205

12041206
try:
12051207
self.index._engine.set_value(self._values, key, value)
12061208
return
1207-
except TypeError:
1209+
except (TypeError, ValueError):
1210+
# ValueError appears in only some builds in CI
12081211
pass
12091212

12101213
self.loc[key] = value

pandas/tests/series/indexing/test_indexing.py

+30
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,36 @@ def test_timedelta_assignment():
654654
tm.assert_series_equal(s, expected)
655655

656656

657+
@pytest.mark.parametrize(
658+
"nat_val,should_cast",
659+
[
660+
(pd.NaT, True),
661+
(np.timedelta64("NaT", "ns"), True),
662+
(np.datetime64("NaT", "ns"), False),
663+
],
664+
)
665+
def test_td64_series_assign_nat(nat_val, should_cast):
666+
# some nat-like values should be cast to timedelta64 when inserting
667+
# into a timedelta64 series. Others should coerce to object
668+
# and retain their dtypes.
669+
base = pd.Series([0, 1, 2], dtype="m8[ns]")
670+
expected = pd.Series([pd.NaT, 1, 2], dtype="m8[ns]")
671+
if not should_cast:
672+
expected = expected.astype(object)
673+
674+
ser = base.copy(deep=True)
675+
ser[0] = nat_val
676+
tm.assert_series_equal(ser, expected)
677+
678+
ser = base.copy(deep=True)
679+
ser.loc[0] = nat_val
680+
tm.assert_series_equal(ser, expected)
681+
682+
ser = base.copy(deep=True)
683+
ser.iloc[0] = nat_val
684+
tm.assert_series_equal(ser, expected)
685+
686+
657687
@pytest.mark.parametrize(
658688
"td",
659689
[

0 commit comments

Comments
 (0)