Skip to content

Commit 3f3c852

Browse files
authored
BUG: construction from dt64/td64 values with td64/dt64 dtype (#38575)
1 parent 46f77b5 commit 3f3c852

File tree

4 files changed

+39
-1
lines changed

4 files changed

+39
-1
lines changed

doc/source/whatsnew/v1.3.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ Datetimelike
182182
^^^^^^^^^^^^
183183
- Bug in :class:`DataFrame` and :class:`Series` constructors sometimes dropping nanoseconds from :class:`Timestamp` (resp. :class:`Timedelta`) ``data``, with ``dtype=datetime64[ns]`` (resp. ``timedelta64[ns]``) (:issue:`38032`)
184184
- Bug in :meth:`DataFrame.first` and :meth:`Series.first` returning two months for offset one month when first day is last calendar day (:issue:`29623`)
185-
-
185+
- Bug in constructing a :class:`DataFrame` or :class:`Series` with mismatched ``datetime64`` data and ``timedelta64`` dtype, or vice-versa, failing to raise ``TypeError`` (:issue:`38575`)
186186

187187
Timedelta
188188
^^^^^^^^^

pandas/core/dtypes/cast.py

+8
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ def maybe_unbox_datetimelike(value: Scalar, dtype: DtypeObj) -> Scalar:
164164
value = value.to_datetime64()
165165
elif isinstance(value, Timedelta):
166166
value = value.to_timedelta64()
167+
168+
if (isinstance(value, np.timedelta64) and dtype.kind == "M") or (
169+
isinstance(value, np.datetime64) and dtype.kind == "m"
170+
):
171+
# numpy allows np.array(dt64values, dtype="timedelta64[ns]") and
172+
# vice-versa, but we do not want to allow this, so we need to
173+
# check explicitly
174+
raise TypeError(f"Cannot cast {repr(value)} to {dtype}")
167175
return value
168176

169177

pandas/tests/dtypes/cast/test_construct_from_scalar.py

+18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import numpy as np
2+
import pytest
23

34
from pandas.core.dtypes.cast import construct_1d_arraylike_from_scalar
45
from pandas.core.dtypes.dtypes import CategoricalDtype
@@ -32,3 +33,20 @@ def test_cast_1d_array_like_from_timedelta():
3233
td = Timedelta(1)
3334
res = construct_1d_arraylike_from_scalar(td, 2, np.dtype("m8[ns]"))
3435
assert res[0] == td
36+
37+
38+
def test_cast_1d_array_like_mismatched_datetimelike():
39+
td = np.timedelta64("NaT", "ns")
40+
dt = np.datetime64("NaT", "ns")
41+
42+
with pytest.raises(TypeError, match="Cannot cast"):
43+
construct_1d_arraylike_from_scalar(td, 2, dt.dtype)
44+
45+
with pytest.raises(TypeError, match="Cannot cast"):
46+
construct_1d_arraylike_from_scalar(np.timedelta64(4, "ns"), 2, dt.dtype)
47+
48+
with pytest.raises(TypeError, match="Cannot cast"):
49+
construct_1d_arraylike_from_scalar(dt, 2, td.dtype)
50+
51+
with pytest.raises(TypeError, match="Cannot cast"):
52+
construct_1d_arraylike_from_scalar(np.datetime64(4, "ns"), 2, td.dtype)

pandas/tests/frame/test_constructors.py

+12
Original file line numberDiff line numberDiff line change
@@ -2962,3 +2962,15 @@ def test_from_timedelta64_scalar_object(self, constructor, request):
29622962

29632963
obj = constructor(td64, dtype=object)
29642964
assert isinstance(get1(obj), np.timedelta64)
2965+
2966+
@pytest.mark.parametrize("cls", [np.datetime64, np.timedelta64])
2967+
def test_from_scalar_datetimelike_mismatched(self, constructor, cls):
2968+
scalar = cls("NaT", "ns")
2969+
dtype = {np.datetime64: "m8[ns]", np.timedelta64: "M8[ns]"}[cls]
2970+
2971+
with pytest.raises(TypeError, match="Cannot cast"):
2972+
constructor(scalar, dtype=dtype)
2973+
2974+
scalar = cls(4, "ns")
2975+
with pytest.raises(TypeError, match="Cannot cast"):
2976+
constructor(scalar, dtype=dtype)

0 commit comments

Comments
 (0)