Skip to content

Commit 76247c1

Browse files
jbrockmendeljreback
authored andcommitted
BUG: Fix inserting of wrong-dtyped NaT, closes #27297 (#27311)
1 parent 41e3b29 commit 76247c1

File tree

4 files changed

+38
-2
lines changed

4 files changed

+38
-2
lines changed

doc/source/whatsnew/v1.0.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Categorical
8787

8888
Datetimelike
8989
^^^^^^^^^^^^
90-
90+
- Bug in :meth:`Series.__setitem__` incorrectly casting ``np.timedelta64("NaT")`` to ``np.datetime64("NaT")`` when inserting into a :class:`Series` with datetime64 dtype (:issue:`27311`)
9191
-
9292
-
9393

pandas/_libs/index.pyx

+3
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,9 @@ cpdef convert_scalar(ndarray arr, object value):
533533
pass
534534
elif isinstance(value, (datetime, np.datetime64, date)):
535535
return Timestamp(value).value
536+
elif util.is_timedelta64_object(value):
537+
# exclude np.timedelta64("NaT") from value != value below
538+
pass
536539
elif value is None or value != value:
537540
return NPY_NAT
538541
elif isinstance(value, str):

pandas/core/internals/blocks.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2589,8 +2589,9 @@ def setitem(self, indexer, value):
25892589
try:
25902590
return super().setitem(indexer, value)
25912591
except (ValueError, TypeError):
2592+
obj_vals = self.values.astype(object)
25922593
newb = make_block(
2593-
self.values.astype(object), placement=self.mgr_locs, klass=ObjectBlock
2594+
obj_vals, placement=self.mgr_locs, klass=ObjectBlock, ndim=self.ndim
25942595
)
25952596
return newb.setitem(indexer, value)
25962597

pandas/tests/series/indexing/test_indexing.py

+32
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,38 @@ 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"), False),
662+
(np.datetime64("NaT", "ns"), True),
663+
],
664+
)
665+
@pytest.mark.parametrize("tz", [None, "UTC"])
666+
def test_dt64_series_assign_nat(nat_val, should_cast, tz):
667+
# some nat-like values should be cast to datetime64 when inserting
668+
# into a datetime64 series. Others should coerce to object
669+
# and retain their dtypes.
670+
dti = pd.date_range("2016-01-01", periods=3, tz=tz)
671+
base = pd.Series(dti)
672+
expected = pd.Series([pd.NaT] + list(dti[1:]), dtype=dti.dtype)
673+
if not should_cast:
674+
expected = expected.astype(object)
675+
676+
ser = base.copy(deep=True)
677+
ser[0] = nat_val
678+
tm.assert_series_equal(ser, expected)
679+
680+
ser = base.copy(deep=True)
681+
ser.loc[0] = nat_val
682+
tm.assert_series_equal(ser, expected)
683+
684+
ser = base.copy(deep=True)
685+
ser.iloc[0] = nat_val
686+
tm.assert_series_equal(ser, expected)
687+
688+
657689
@pytest.mark.parametrize(
658690
"nat_val,should_cast",
659691
[

0 commit comments

Comments
 (0)