diff --git a/doc/source/whatsnew/v3.0.3.rst b/doc/source/whatsnew/v3.0.3.rst index 9e9810b782383..dce11bd775b1c 100644 --- a/doc/source/whatsnew/v3.0.3.rst +++ b/doc/source/whatsnew/v3.0.3.rst @@ -15,6 +15,7 @@ Fixed regressions ~~~~~~~~~~~~~~~~~ - Fixed reading of Parquet files with timezone-aware timestamps or localizing of a timeseries with a ``pytz`` timezone when an older version of ``pytz`` was installed (:issue:`64978`) +- Fixed regression in :func:`to_timedelta` ignoring the ``unit`` argument for round float values when mixed with non-round floats in a list (:issue:`65150`) - Fixed regression in :meth:`Timedelta.round`, :meth:`Timedelta.floor`, and :meth:`Timedelta.ceil` raising ``ZeroDivisionError`` for sub-second ``freq`` (:issue:`64828`) .. --------------------------------------------------------------------------- diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index e2075f1f88270..a077ec78bb741 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -488,13 +488,15 @@ def array_to_timedelta64( if item == NPY_NAT: ival = NPY_NAT else: - ival = _numeric_to_td64ns(item, parsed_unit, int_reso) + # GH#65150 match the pattern in tslib.pyx: update creso + # first, then convert using creso as the output resolution. item_reso = int_reso - state.update_creso(item_reso) if infer_reso: creso = state.creso + ival = _numeric_to_td64ns(item, parsed_unit, creso) + elif is_float_object(item): int_item = int(item) if item == int_item: @@ -505,21 +507,20 @@ def array_to_timedelta64( if item == NPY_NAT: ival = NPY_NAT else: - ival = _numeric_to_td64ns(item, parsed_unit, int_reso) item_reso = int_reso - state.update_creso(item_reso) if infer_reso: creso = state.creso - else: - ival = _numeric_to_td64ns(item, parsed_unit, NPY_FR_ns) + ival = _numeric_to_td64ns(item, parsed_unit, creso) + else: item_reso = NPY_FR_ns - int_reso = NPY_FR_ns state.update_creso(item_reso) if infer_reso: creso = state.creso + ival = _numeric_to_td64ns(item, parsed_unit, creso) + elif isinstance(item, Day): # GH#64240: support Day offsets in list-like conversion ival = item.n * 86400 diff --git a/pandas/tests/tools/test_to_timedelta.py b/pandas/tests/tools/test_to_timedelta.py index 83f9260791c07..cfd20c7bb179f 100644 --- a/pandas/tests/tools/test_to_timedelta.py +++ b/pandas/tests/tools/test_to_timedelta.py @@ -354,6 +354,18 @@ def test_to_timedelta_unit_non_round_floats(self): result2 = to_timedelta(arr2, unit="s") assert result2.unit == "ns" + def test_to_timedelta_unit_mixed_round_and_non_round_floats(self): + # GH#65150 - round floats mixed with non-round floats should + # respect the unit for all values + expected = to_timedelta(["0 days 00:00:01", "0 days 00:00:01.01"]).as_unit("ns") + + result = to_timedelta([1.0, 1.01], unit="s") + tm.assert_index_equal(result, expected) + + # Also test integers mixed with non-round floats + result2 = to_timedelta([1, 1.01], unit="s") + tm.assert_index_equal(result2, expected) + def test_float_to_timedelta_raise_near_bounds(self): # GH#57366 oneday_in_ns = 1e9 * 60 * 60 * 24 @@ -438,7 +450,7 @@ def test_uint64_to_timedelta_coerce(self): arr = np.array([uint64_max], dtype=np.uint64) result = to_timedelta(arr, unit="ns", errors="coerce") - expected = TimedeltaIndex([pd.NaT]) + expected = TimedeltaIndex([pd.NaT], dtype="m8[ns]") tm.assert_index_equal(result, expected) # scalar