Skip to content
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ Other Deprecations
- Deprecated :meth:`Timestamp.utcnow`, use ``Timestamp.now("UTC")`` instead (:issue:`56680`)
- Deprecated allowing non-keyword arguments in :meth:`Series.to_markdown` except ``buf``. (:issue:`57280`)
- Deprecated allowing non-keyword arguments in :meth:`Series.to_string` except ``buf``. (:issue:`57280`)
- Deprecated behavior of :meth:`Series.dt.to_pytimedelta`, in a future version this will return a :class:`Series` containing python ``datetime.timedelta`` objects instead of an ``ndarray`` of timedelta; this matches the behavior of other :meth:`Series.dt` properties (:issue:`57463`)
-

.. ---------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions pandas/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ def pytest_collection_modifyitems(items, config) -> None:
("SeriesGroupBy.idxmax", "The behavior of Series.idxmax"),
# Docstring divides by zero to show behavior difference
("missing.mask_zero_div_zero", "divide by zero encountered"),
(
"to_pytimedelta",
"The behavior of TimedeltaProperties.to_pytimedelta is deprecated",
),
(
"pandas.core.generic.NDFrame.first",
"first is deprecated and will be removed in a future version. "
Expand Down
18 changes: 18 additions & 0 deletions pandas/core/indexes/accessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,15 @@ def _delegate_method(self, name: str, *args, **kwargs):
return result

def to_pytimedelta(self):
# GH#57463
warnings.warn(
f"The behavior of {type(self).__name__}.to_pytimedelta is deprecated, "
"in a future version this will return a Series containing python "
"datetime.timedelta objects instead of an ndarray. To retain "
"the old behavior, call `np.array` on the result",
FutureWarning,
stacklevel=find_stack_level(),
)
return cast(ArrowExtensionArray, self._parent.array)._dt_to_pytimedelta()

def to_pydatetime(self) -> Series:
Expand Down Expand Up @@ -461,6 +470,15 @@ def to_pytimedelta(self) -> np.ndarray:
datetime.timedelta(days=2), datetime.timedelta(days=3),
datetime.timedelta(days=4)], dtype=object)
"""
# GH#57463
warnings.warn(
f"The behavior of {type(self).__name__}.to_pytimedelta is deprecated, "
"in a future version this will return a Series containing python "
"datetime.timedelta objects instead of an ndarray. To retain "
"the old behavior, call `np.array` on the result",
FutureWarning,
stacklevel=find_stack_level(),
)
return self._get_values().to_pytimedelta()

@property
Expand Down
8 changes: 6 additions & 2 deletions pandas/tests/extension/test_arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2860,12 +2860,16 @@ def test_dt_to_pytimedelta():
data = [timedelta(1, 2, 3), timedelta(1, 2, 4)]
ser = pd.Series(data, dtype=ArrowDtype(pa.duration("ns")))

result = ser.dt.to_pytimedelta()
msg = "The behavior of ArrowTemporalProperties.to_pytimedelta is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ser.dt.to_pytimedelta()
expected = np.array(data, dtype=object)
tm.assert_numpy_array_equal(result, expected)
assert all(type(res) is timedelta for res in result)

expected = ser.astype("timedelta64[ns]").dt.to_pytimedelta()
msg = "The behavior of TimedeltaProperties.to_pytimedelta is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
expected = ser.astype("timedelta64[ns]").dt.to_pytimedelta()
tm.assert_numpy_array_equal(result, expected)


Expand Down
3 changes: 3 additions & 0 deletions pandas/tests/series/accessors/test_cat_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ def test_dt_accessor_api_for_categorical(self, idx):
if func == "to_period" and getattr(idx, "tz", None) is not None:
# dropping TZ
warn_cls.append(UserWarning)
if func == "to_pytimedelta":
# deprecated to return Index[object]
warn_cls.append(FutureWarning)
if warn_cls:
warn_cls = tuple(warn_cls)
else:
Expand Down
4 changes: 3 additions & 1 deletion pandas/tests/series/accessors/test_dt_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ def test_dt_namespace_accessor_timedelta(self):
assert isinstance(result, DataFrame)
tm.assert_index_equal(result.index, ser.index)

result = ser.dt.to_pytimedelta()
msg = "The behavior of TimedeltaProperties.to_pytimedelta is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ser.dt.to_pytimedelta()
assert isinstance(result, np.ndarray)
assert result.dtype == object

Expand Down