diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst index 9f2bbaa8d5120..5386e10c695c7 100644 --- a/doc/source/whatsnew/v1.5.0.rst +++ b/doc/source/whatsnew/v1.5.0.rst @@ -479,6 +479,8 @@ Datetimelike Timedelta ^^^^^^^^^ - Bug in :func:`astype_nansafe` astype("timedelta64[ns]") fails when np.nan is included (:issue:`45798`) +- Bug in constructing a :class:`Timedelta` with a ``np.timedelta64`` object and a ``unit`` sometimes silently overflowing and returning incorrect results instead of raising ``OutOfBoundsTimedelta`` (:issue:`46827`) +- Time Zones ^^^^^^^^^^ diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index 8f87bfe0b8c7c..7d055b1cb1049 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -277,6 +277,16 @@ cdef str npy_unit_to_abbrev(NPY_DATETIMEUNIT unit): return "M" elif unit == NPY_DATETIMEUNIT.NPY_FR_Y: return "Y" + + # Checks for not-really-supported units go at the end, as we don't expect + # to see these often + elif unit == NPY_DATETIMEUNIT.NPY_FR_ps: + return "ps" + elif unit == NPY_DATETIMEUNIT.NPY_FR_fs: + return "fs" + elif unit == NPY_DATETIMEUNIT.NPY_FR_as: + return "as" + else: raise NotImplementedError(unit) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 6606158aea807..39a3414ca5167 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1487,8 +1487,6 @@ class Timedelta(_Timedelta): elif PyDelta_Check(value): value = convert_to_timedelta64(value, 'ns') elif is_timedelta64_object(value): - if unit is not None: - value = value.astype(f'timedelta64[{unit}]') value = ensure_td64ns(value) elif is_tick_object(value): value = np.timedelta64(value.nanos, 'ns') diff --git a/pandas/tests/scalar/timedelta/test_constructors.py b/pandas/tests/scalar/timedelta/test_constructors.py index 34b725eb9fe77..7fc7bd3a5a74d 100644 --- a/pandas/tests/scalar/timedelta/test_constructors.py +++ b/pandas/tests/scalar/timedelta/test_constructors.py @@ -13,6 +13,21 @@ ) +def test_construct_from_td64_with_unit(): + # ignore the unit, as it may cause silently overflows leading to incorrect + # results, and in non-overflow cases is irrelevant GH#46827 + obj = np.timedelta64(123456789, "h") + + with pytest.raises(OutOfBoundsTimedelta, match="123456789 hours"): + Timedelta(obj, unit="ps") + + with pytest.raises(OutOfBoundsTimedelta, match="123456789 hours"): + Timedelta(obj, unit="ns") + + with pytest.raises(OutOfBoundsTimedelta, match="123456789 hours"): + Timedelta(obj) + + def test_construction(): expected = np.timedelta64(10, "D").astype("m8[ns]").view("i8") assert Timedelta(10, unit="d").value == expected