Skip to content

Commit e7e5b61

Browse files
authored
BUG: DatetimeArray._from_sequence accepting bool dtype (#32668)
1 parent bab3b1f commit e7e5b61

File tree

5 files changed

+42
-10
lines changed

5 files changed

+42
-10
lines changed

doc/source/whatsnew/v1.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ Datetimelike
247247
- Bug in :class:`Timestamp` where constructing :class:`Timestamp` with dateutil timezone less than 128 nanoseconds before daylight saving time switch from winter to summer would result in nonexistent time (:issue:`31043`)
248248
- Bug in :meth:`Period.to_timestamp`, :meth:`Period.start_time` with microsecond frequency returning a timestamp one nanosecond earlier than the correct time (:issue:`31475`)
249249
- :class:`Timestamp` raising confusing error message when year, month or day is missing (:issue:`31200`)
250+
- Bug in :class:`DatetimeIndex` constructor incorrectly accepting ``bool``-dtyped inputs (:issue:`32668`)
250251

251252
Timedelta
252253
^^^^^^^^^

pandas/core/arrays/datetimes.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from pandas.core.dtypes.common import (
2424
_INT64_DTYPE,
2525
_NS_DTYPE,
26+
is_bool_dtype,
2627
is_categorical_dtype,
2728
is_datetime64_any_dtype,
2829
is_datetime64_dtype,
@@ -1903,32 +1904,36 @@ def maybe_convert_dtype(data, copy):
19031904
------
19041905
TypeError : PeriodDType data is passed
19051906
"""
1906-
if is_float_dtype(data):
1907+
if not hasattr(data, "dtype"):
1908+
# e.g. collections.deque
1909+
return data, copy
1910+
1911+
if is_float_dtype(data.dtype):
19071912
# Note: we must cast to datetime64[ns] here in order to treat these
19081913
# as wall-times instead of UTC timestamps.
19091914
data = data.astype(_NS_DTYPE)
19101915
copy = False
19111916
# TODO: deprecate this behavior to instead treat symmetrically
19121917
# with integer dtypes. See discussion in GH#23675
19131918

1914-
elif is_timedelta64_dtype(data):
1919+
elif is_timedelta64_dtype(data.dtype) or is_bool_dtype(data.dtype):
19151920
# GH#29794 enforcing deprecation introduced in GH#23539
19161921
raise TypeError(f"dtype {data.dtype} cannot be converted to datetime64[ns]")
1917-
elif is_period_dtype(data):
1922+
elif is_period_dtype(data.dtype):
19181923
# Note: without explicitly raising here, PeriodIndex
19191924
# test_setops.test_join_does_not_recur fails
19201925
raise TypeError(
19211926
"Passing PeriodDtype data is invalid. Use `data.to_timestamp()` instead"
19221927
)
19231928

1924-
elif is_categorical_dtype(data):
1929+
elif is_categorical_dtype(data.dtype):
19251930
# GH#18664 preserve tz in going DTI->Categorical->DTI
19261931
# TODO: cases where we need to do another pass through this func,
19271932
# e.g. the categories are timedelta64s
19281933
data = data.categories.take(data.codes, fill_value=NaT)._values
19291934
copy = False
19301935

1931-
elif is_extension_array_dtype(data) and not is_datetime64tz_dtype(data):
1936+
elif is_extension_array_dtype(data.dtype) and not is_datetime64tz_dtype(data.dtype):
19321937
# Includes categorical
19331938
# TODO: We have no tests for these
19341939
data = np.array(data, dtype=np.object_)

pandas/core/series.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2666,9 +2666,9 @@ def combine(self, other, func, fill_value=None) -> "Series":
26662666
new_values = [func(lv, other) for lv in self._values]
26672667
new_name = self.name
26682668

2669-
if is_categorical_dtype(self.values):
2669+
if is_categorical_dtype(self.dtype):
26702670
pass
2671-
elif is_extension_array_dtype(self.values):
2671+
elif is_extension_array_dtype(self.dtype):
26722672
# The function can return something of any type, so check
26732673
# if the type is compatible with the calling EA.
26742674
new_values = try_cast_to_ea(self._values, new_values)

pandas/core/tools/datetimes.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,18 @@ def _convert_listlike_datetimes(
359359
# warn if passing timedelta64, raise for PeriodDtype
360360
# NB: this must come after unit transformation
361361
orig_arg = arg
362-
arg, _ = maybe_convert_dtype(arg, copy=False)
362+
try:
363+
arg, _ = maybe_convert_dtype(arg, copy=False)
364+
except TypeError:
365+
if errors == "coerce":
366+
result = np.array(["NaT"], dtype="datetime64[ns]").repeat(len(arg))
367+
return DatetimeIndex(result, name=name)
368+
elif errors == "ignore":
369+
from pandas import Index
370+
371+
result = Index(arg, name=name)
372+
return result
373+
raise
363374

364375
arg = ensure_object(arg)
365376
require_iso8601 = False

pandas/tests/arrays/test_datetimes.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,26 @@ def test_non_array_raises(self):
8989
with pytest.raises(ValueError, match="list"):
9090
DatetimeArray([1, 2, 3])
9191

92-
def test_other_type_raises(self):
92+
def test_bool_dtype_raises(self):
93+
arr = np.array([1, 2, 3], dtype="bool")
94+
9395
with pytest.raises(
9496
ValueError, match="The dtype of 'values' is incorrect.*bool"
9597
):
96-
DatetimeArray(np.array([1, 2, 3], dtype="bool"))
98+
DatetimeArray(arr)
99+
100+
msg = r"dtype bool cannot be converted to datetime64\[ns\]"
101+
with pytest.raises(TypeError, match=msg):
102+
DatetimeArray._from_sequence(arr)
103+
104+
with pytest.raises(TypeError, match=msg):
105+
sequence_to_dt64ns(arr)
106+
107+
with pytest.raises(TypeError, match=msg):
108+
pd.DatetimeIndex(arr)
109+
110+
with pytest.raises(TypeError, match=msg):
111+
pd.to_datetime(arr)
97112

98113
def test_incorrect_dtype_raises(self):
99114
with pytest.raises(ValueError, match="Unexpected value for 'dtype'."):

0 commit comments

Comments
 (0)