Skip to content

Commit eaddc1d

Browse files
authored
BUG: to_timedelta with ArrowDtype(pa.duration) (#54298)
* BUG: to_timedelta with ArrowDtype(pa.duration) * Add GH number
1 parent 818618e commit eaddc1d

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

doc/source/whatsnew/v2.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ Timedelta
638638
- :meth:`TimedeltaIndex.map` with ``na_action="ignore"`` now works as expected (:issue:`51644`)
639639
- Bug in :class:`TimedeltaIndex` division or multiplication leading to ``.freq`` of "0 Days" instead of ``None`` (:issue:`51575`)
640640
- Bug in :class:`Timedelta` with Numpy timedelta64 objects not properly raising ``ValueError`` (:issue:`52806`)
641+
- Bug in :func:`to_timedelta` converting :class:`Series` or :class:`DataFrame` containing :class:`ArrowDtype` of ``pyarrow.duration`` to numpy ``timedelta64`` (:issue:`54298`)
641642
- Bug in :meth:`Timedelta.__hash__`, raising an ``OutOfBoundsTimedelta`` on certain large values of second resolution (:issue:`54037`)
642643
- Bug in :meth:`Timedelta.round` with values close to the implementation bounds returning incorrect results instead of raising ``OutOfBoundsTimedelta`` (:issue:`51494`)
643644
- Bug in :meth:`arrays.TimedeltaArray.map` and :meth:`TimedeltaIndex.map`, where the supplied callable operated array-wise instead of element-wise (:issue:`51977`)

pandas/core/tools/timedeltas.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from pandas.util._exceptions import find_stack_level
2424

2525
from pandas.core.dtypes.common import is_list_like
26+
from pandas.core.dtypes.dtypes import ArrowDtype
2627
from pandas.core.dtypes.generic import (
2728
ABCIndex,
2829
ABCSeries,
@@ -31,6 +32,7 @@
3132
from pandas.core.arrays.timedeltas import sequence_to_td64ns
3233

3334
if TYPE_CHECKING:
35+
from collections.abc import Hashable
3436
from datetime import timedelta
3537

3638
from pandas._libs.tslibs.timedeltas import UnitChoices
@@ -242,17 +244,23 @@ def _coerce_scalar_to_timedelta_type(
242244

243245

244246
def _convert_listlike(
245-
arg, unit=None, errors: DateTimeErrorChoices = "raise", name=None
247+
arg,
248+
unit: UnitChoices | None = None,
249+
errors: DateTimeErrorChoices = "raise",
250+
name: Hashable | None = None,
246251
):
247252
"""Convert a list of objects to a timedelta index object."""
248-
if isinstance(arg, (list, tuple)) or not hasattr(arg, "dtype"):
253+
arg_dtype = getattr(arg, "dtype", None)
254+
if isinstance(arg, (list, tuple)) or arg_dtype is None:
249255
# This is needed only to ensure that in the case where we end up
250256
# returning arg (errors == "ignore"), and where the input is a
251257
# generator, we return a useful list-like instead of a
252258
# used-up generator
253259
if not hasattr(arg, "__array__"):
254260
arg = list(arg)
255261
arg = np.array(arg, dtype=object)
262+
elif isinstance(arg_dtype, ArrowDtype) and arg_dtype.kind == "m":
263+
return arg
256264

257265
try:
258266
td64arr = sequence_to_td64ns(arg, unit=unit, errors=errors, copy=False)[0]

pandas/tests/tools/test_to_timedelta.py

+9
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,12 @@ def test_from_numeric_arrow_dtype(any_numeric_ea_dtype):
306306
result = to_timedelta(ser)
307307
expected = Series([1, 2], dtype="timedelta64[ns]")
308308
tm.assert_series_equal(result, expected)
309+
310+
311+
@pytest.mark.parametrize("unit", ["ns", "ms"])
312+
def test_from_timedelta_arrow_dtype(unit):
313+
# GH 54298
314+
pytest.importorskip("pyarrow")
315+
expected = Series([timedelta(1)], dtype=f"duration[{unit}][pyarrow]")
316+
result = to_timedelta(expected)
317+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)