Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`)

.. ---------------------------------------------------------------------------
Expand Down
15 changes: 8 additions & 7 deletions pandas/_libs/tslibs/timedeltas.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down
13 changes: 12 additions & 1 deletion pandas/tests/tools/test_to_timedelta.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,17 @@ 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
result = to_timedelta([1.0, 1.01], unit="s")
expected = to_timedelta(np.array([1.0, 1.01]), unit="s")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes that this works correctly for arrays (instead of lists), I don't know if that actually is tested separately?

Could also create expected with to_timedelta(["0 days 00:00:01", "0 days 00:00:01.01"]), that seems more explicit / safer anyway

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will update

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
Expand Down Expand Up @@ -438,7 +449,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]")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this change related exactly?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its a side-effect, but it matches the to_datetime behavior

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the result that changes, not the expected? (that already correctly gives "s" on main)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, understood

tm.assert_index_equal(result, expected)

# scalar
Expand Down
Loading