Skip to content

Commit f4d3806

Browse files
dsaxtonhweecat
authored andcommitted
BUG: Raise when casting NaT to int (pandas-dev#28492)
* BUG: Raise when casting NaT to int * Add release note * Add PR number * Use isna * Parametrize test * Check all integer dtypes * Fix merge * Edit release note * Check for np.int64 * Handle timedelta64 * Add astype_nansafe datetime tests * Add test for NaT object casting
1 parent 7b0714c commit f4d3806

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

doc/source/whatsnew/v1.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ Datetimelike
773773
- Bug in :class:`Timestamp` subtraction when subtracting a :class:`Timestamp` from a ``np.datetime64`` object incorrectly raising ``TypeError`` (:issue:`28286`)
774774
- Addition and subtraction of integer or integer-dtype arrays with :class:`Timestamp` will now raise ``NullFrequencyError`` instead of ``ValueError`` (:issue:`28268`)
775775
- Bug in :class:`Series` and :class:`DataFrame` with integer dtype failing to raise ``TypeError`` when adding or subtracting a ``np.datetime64`` object (:issue:`28080`)
776+
- Bug in :meth:`Series.astype`, :meth:`Index.astype`, and :meth:`DataFrame.astype` failing to handle ``NaT`` when casting to an integer dtype (:issue:`28492`)
776777
- Bug in :class:`Week` with ``weekday`` incorrectly raising ``AttributeError`` instead of ``TypeError`` when adding or subtracting an invalid type (:issue:`28530`)
777778
- Bug in :class:`DataFrame` arithmetic operations when operating with a :class:`Series` with dtype `'timedelta64[ns]'` (:issue:`28049`)
778779
- Bug in :func:`pandas.core.groupby.generic.SeriesGroupBy.apply` raising ``ValueError`` when a column in the original DataFrame is a datetime and the column labels are not standard integers (:issue:`28247`)

pandas/core/dtypes/cast.py

+4
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,8 @@ def astype_nansafe(arr, dtype, copy: bool = True, skipna: bool = False):
823823
if is_object_dtype(dtype):
824824
return tslib.ints_to_pydatetime(arr.view(np.int64))
825825
elif dtype == np.int64:
826+
if isna(arr).any():
827+
raise ValueError("Cannot convert NaT values to integer")
826828
return arr.view(dtype)
827829

828830
# allow frequency conversions
@@ -835,6 +837,8 @@ def astype_nansafe(arr, dtype, copy: bool = True, skipna: bool = False):
835837
if is_object_dtype(dtype):
836838
return tslibs.ints_to_pytimedelta(arr.view(np.int64))
837839
elif dtype == np.int64:
840+
if isna(arr).any():
841+
raise ValueError("Cannot convert NaT values to integer")
838842
return arr.view(dtype)
839843

840844
if dtype not in [_INT64_DTYPE, _TD_DTYPE]:

pandas/tests/dtypes/test_common.py

+41
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pandas.util._test_decorators as td
77

8+
from pandas.core.dtypes.cast import astype_nansafe
89
import pandas.core.dtypes.common as com
910
from pandas.core.dtypes.dtypes import (
1011
CategoricalDtype,
@@ -13,6 +14,7 @@
1314
IntervalDtype,
1415
PeriodDtype,
1516
)
17+
from pandas.core.dtypes.missing import isna
1618

1719
import pandas as pd
1820
from pandas.conftest import (
@@ -709,3 +711,42 @@ def test__get_dtype_fails(input_param, expected_error_message):
709711
)
710712
def test__is_dtype_type(input_param, result):
711713
assert com._is_dtype_type(input_param, lambda tipo: tipo == result)
714+
715+
716+
@pytest.mark.parametrize("val", [np.datetime64("NaT"), np.timedelta64("NaT")])
717+
@pytest.mark.parametrize("typ", [np.int64])
718+
def test_astype_nansafe(val, typ):
719+
arr = np.array([val])
720+
721+
msg = "Cannot convert NaT values to integer"
722+
with pytest.raises(ValueError, match=msg):
723+
astype_nansafe(arr, dtype=typ)
724+
725+
726+
@pytest.mark.parametrize("from_type", [np.datetime64, np.timedelta64])
727+
@pytest.mark.parametrize(
728+
"to_type",
729+
[
730+
np.uint8,
731+
np.uint16,
732+
np.uint32,
733+
np.int8,
734+
np.int16,
735+
np.int32,
736+
np.float16,
737+
np.float32,
738+
],
739+
)
740+
def test_astype_datetime64_bad_dtype_raises(from_type, to_type):
741+
arr = np.array([from_type("2018")])
742+
743+
with pytest.raises(TypeError, match="cannot astype"):
744+
astype_nansafe(arr, dtype=to_type)
745+
746+
747+
@pytest.mark.parametrize("from_type", [np.datetime64, np.timedelta64])
748+
def test_astype_object_preserves_datetime_na(from_type):
749+
arr = np.array([from_type("NaT")])
750+
result = astype_nansafe(arr, dtype="object")
751+
752+
assert isna(result)[0]

0 commit comments

Comments
 (0)