Skip to content

Commit 7b61952

Browse files
jbrockmendeljreback
authored andcommitted
Fix _can_hold_element for datetimelike blocks (#27347)
1 parent d4e2734 commit 7b61952

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

pandas/core/dtypes/missing.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ def is_valid_nat_for_dtype(obj, dtype):
574574
-------
575575
bool
576576
"""
577-
if not isna(obj):
577+
if not lib.is_scalar(obj) or not isna(obj):
578578
return False
579579
if dtype.kind == "M":
580580
return not isinstance(obj, np.timedelta64)

pandas/core/internals/blocks.py

+33-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99

1010
from pandas._libs import NaT, lib, tslib, tslibs
1111
import pandas._libs.internals as libinternals
12-
from pandas._libs.tslibs import Timedelta, conversion, is_null_datetimelike
12+
from pandas._libs.tslibs import Timedelta, conversion
13+
from pandas._libs.tslibs.timezones import tz_compare
1314
from pandas.util._validators import validate_bool_kwarg
1415

1516
from pandas.core.dtypes.cast import (
@@ -60,7 +61,13 @@
6061
ABCPandasArray,
6162
ABCSeries,
6263
)
63-
from pandas.core.dtypes.missing import _isna_compat, array_equivalent, isna, notna
64+
from pandas.core.dtypes.missing import (
65+
_isna_compat,
66+
array_equivalent,
67+
is_valid_nat_for_dtype,
68+
isna,
69+
notna,
70+
)
6471

6572
import pandas.core.algorithms as algos
6673
from pandas.core.arrays import (
@@ -2248,14 +2255,17 @@ def _astype(self, dtype, **kwargs):
22482255
def _can_hold_element(self, element):
22492256
tipo = maybe_infer_dtype_type(element)
22502257
if tipo is not None:
2251-
return tipo == _NS_DTYPE or tipo == np.int64
2258+
return is_dtype_equal(tipo, self.dtype)
2259+
elif element is NaT:
2260+
return True
22522261
elif isinstance(element, datetime):
2262+
if self.is_datetimetz:
2263+
return tz_compare(element.tzinfo, self.dtype.tz)
22532264
return element.tzinfo is None
22542265
elif is_integer(element):
22552266
return element == tslibs.iNaT
22562267

2257-
# TODO: shouldnt we exclude timedelta64("NaT")? See GH#27297
2258-
return isna(element)
2268+
return is_valid_nat_for_dtype(element, self.dtype)
22592269

22602270
def _coerce_values(self, values):
22612271
return values.view("i8")
@@ -2275,8 +2285,10 @@ def _try_coerce_args(self, other):
22752285
-------
22762286
base-type other
22772287
"""
2278-
if is_null_datetimelike(other):
2288+
if is_valid_nat_for_dtype(other, self.dtype):
22792289
other = tslibs.iNaT
2290+
elif is_integer(other) and other == tslibs.iNaT:
2291+
pass
22802292
elif isinstance(other, (datetime, np.datetime64, date)):
22812293
other = self._box_func(other)
22822294
if getattr(other, "tz") is not None:
@@ -2359,6 +2371,8 @@ class DatetimeTZBlock(ExtensionBlock, DatetimeBlock):
23592371
is_datetimetz = True
23602372
is_extension = True
23612373

2374+
_can_hold_element = DatetimeBlock._can_hold_element
2375+
23622376
@property
23632377
def _holder(self):
23642378
return DatetimeArray
@@ -2465,8 +2479,10 @@ def _try_coerce_args(self, other):
24652479
# add the tz back
24662480
other = self._holder(other, dtype=self.dtype)
24672481

2468-
elif is_null_datetimelike(other):
2482+
elif is_valid_nat_for_dtype(other, self.dtype):
24692483
other = tslibs.iNaT
2484+
elif is_integer(other) and other == tslibs.iNaT:
2485+
pass
24702486
elif isinstance(other, self._holder):
24712487
if other.tz != self.values.tz:
24722488
raise ValueError("incompatible or non tz-aware value")
@@ -2606,10 +2622,16 @@ def _box_func(self):
26062622
def _can_hold_element(self, element):
26072623
tipo = maybe_infer_dtype_type(element)
26082624
if tipo is not None:
2625+
# TODO: remove the np.int64 support once coerce_values and
2626+
# _try_coerce_args both coerce to m8[ns] and not i8.
26092627
return issubclass(tipo.type, (np.timedelta64, np.int64))
26102628
elif element is NaT:
26112629
return True
2612-
return is_integer(element) or isinstance(element, (timedelta, np.timedelta64))
2630+
elif isinstance(element, (timedelta, np.timedelta64)):
2631+
return True
2632+
elif is_integer(element):
2633+
return element == tslibs.iNaT
2634+
return is_valid_nat_for_dtype(element, self.dtype)
26132635

26142636
def fillna(self, value, **kwargs):
26152637

@@ -2645,8 +2667,10 @@ def _try_coerce_args(self, other):
26452667
base-type other
26462668
"""
26472669

2648-
if is_null_datetimelike(other):
2670+
if is_valid_nat_for_dtype(other, self.dtype):
26492671
other = tslibs.iNaT
2672+
elif is_integer(other) and other == tslibs.iNaT:
2673+
pass
26502674
elif isinstance(other, (timedelta, np.timedelta64)):
26512675
other = Timedelta(other).value
26522676
elif hasattr(other, "dtype") and is_timedelta64_dtype(other):

0 commit comments

Comments
 (0)