diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index 4244217da7865..c4dda24f857d9 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -1308,7 +1308,7 @@ def maybe_cast_to_datetime( # TODO: _from_sequence would raise ValueError in cases where # _ensure_nanosecond_dtype raises TypeError dtype = cast(np.dtype, dtype) - dtype = _ensure_nanosecond_dtype(dtype) + _ensure_nanosecond_dtype(dtype) res = TimedeltaArray._from_sequence(value, dtype=dtype) return res @@ -1319,7 +1319,7 @@ def maybe_cast_to_datetime( vdtype = getattr(value, "dtype", None) if is_datetime64 or is_datetime64tz: - dtype = _ensure_nanosecond_dtype(dtype) + _ensure_nanosecond_dtype(dtype) value = np.array(value, copy=False) @@ -1437,17 +1437,9 @@ def sanitize_to_nanoseconds(values: np.ndarray, copy: bool = False) -> np.ndarra return values -def _ensure_nanosecond_dtype(dtype: DtypeObj) -> DtypeObj: +def _ensure_nanosecond_dtype(dtype: DtypeObj) -> None: """ - Convert dtypes with granularity less than nanosecond to nanosecond - - >>> _ensure_nanosecond_dtype(np.dtype("M8[s]")) - dtype('>> _ensure_nanosecond_dtype(np.dtype("m8[ps]")) - Traceback (most recent call last): - ... - TypeError: cannot convert timedeltalike to dtype [timedelta64[ps]] + Reject datetime/timedelta dtypes with granularity different from ns """ msg = ( f"The '{dtype.name}' dtype has no unit. " @@ -1459,28 +1451,13 @@ def _ensure_nanosecond_dtype(dtype: DtypeObj) -> DtypeObj: if not isinstance(dtype, np.dtype): # i.e. datetime64tz - pass + return - elif dtype.kind == "M" and dtype != DT64NS_DTYPE: - # pandas supports dtype whose granularity is less than [ns] - # e.g., [ps], [fs], [as] - if dtype <= np.dtype("M8[ns]"): - if dtype.name == "datetime64": - raise ValueError(msg) - dtype = DT64NS_DTYPE - else: - raise TypeError(f"cannot convert datetimelike to dtype [{dtype}]") + if dtype.name in ("datetime64", "timedelta64"): + raise ValueError(msg) - elif dtype.kind == "m" and dtype != TD64NS_DTYPE: - # pandas supports dtype whose granularity is less than [ns] - # e.g., [ps], [fs], [as] - if dtype <= np.dtype("m8[ns]"): - if dtype.name == "timedelta64": - raise ValueError(msg) - dtype = TD64NS_DTYPE - else: - raise TypeError(f"cannot convert timedeltalike to dtype [{dtype}]") - return dtype + if dtype not in (TD64NS_DTYPE, DT64NS_DTYPE): + raise TypeError("Only [ns] granularity is supported for timedelta and datetime") # TODO: other value-dependent functions to standardize here include diff --git a/pandas/tests/series/test_constructors.py b/pandas/tests/series/test_constructors.py index f79714ae6455c..2959479f426fc 100644 --- a/pandas/tests/series/test_constructors.py +++ b/pandas/tests/series/test_constructors.py @@ -1578,6 +1578,14 @@ def test_convert_non_ns(self): expected = Series(date_range("20130101 00:00:01", periods=3, freq="s")) tm.assert_series_equal(ser, expected) + # try to construct from a sequence asking for non-ns timedelta64 + with pytest.raises(TypeError, match=r"Only \[ns\] granularity is supported"): + Series([1000000, 200000, 3000000], dtype="timedelta64[s]") + + # try to construct from a sequence asking for non-ns datetime64 + with pytest.raises(TypeError, match=r"Only \[ns\] granularity is supported"): + Series([1000000, 200000, 3000000], dtype="datetime64[s]") + @pytest.mark.parametrize( "index", [ @@ -1642,8 +1650,8 @@ def test_constructor_generic_timestamp_no_frequency(self, dtype, request): @pytest.mark.parametrize( "dtype,msg", [ - ("m8[ps]", "cannot convert timedeltalike"), - ("M8[ps]", "cannot convert datetimelike"), + (r"m8[ps]", r"Only \[ns\] granularity is supported"), + (r"M8[ps]", r"Only \[ns\] granularity is supported"), ], ) def test_constructor_generic_timestamp_bad_frequency(self, dtype, msg): @@ -1886,22 +1894,6 @@ def test_constructor_dtype_timedelta_alternative_construct(self): expected = Series(pd.to_timedelta([1000000, 200000, 3000000], unit="ns")) tm.assert_series_equal(result, expected) - def test_constructor_dtype_timedelta_ns_s(self): - # GH#35465 - result = Series([1000000, 200000, 3000000], dtype="timedelta64[ns]") - expected = Series([1000000, 200000, 3000000], dtype="timedelta64[s]") - tm.assert_series_equal(result, expected) - - def test_constructor_dtype_timedelta_ns_s_astype_int64(self): - # GH#35465 - result = Series([1000000, 200000, 3000000], dtype="timedelta64[ns]").astype( - "int64" - ) - expected = Series([1000000, 200000, 3000000], dtype="timedelta64[s]").astype( - "int64" - ) - tm.assert_series_equal(result, expected) - @pytest.mark.filterwarnings( "ignore:elementwise comparison failed:DeprecationWarning" )