Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,7 @@ Timedelta
- Bug in :class:`Timedelta` constructor failing to raise when passed an invalid keyword (:issue:`53801`)
- Bug in :meth:`DataFrame.cumsum` which was raising ``IndexError`` if dtype is ``timedelta64[ns]`` (:issue:`57956`)
- Bug in multiplication operations with ``timedelta64`` dtype failing to raise ``TypeError`` when multiplying by ``bool`` objects or dtypes (:issue:`58054`)
- Bug in multiplication operations with ``timedelta64`` dtype incorrectly raising when multiplying by numpy-nullable dtypes or pyarrow integer dtypes (:issue:`58054`)

Timezones
^^^^^^^^^
Expand Down
10 changes: 9 additions & 1 deletion pandas/core/arrays/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@
is_string_dtype,
pandas_dtype,
)
from pandas.core.dtypes.dtypes import ExtensionDtype
from pandas.core.dtypes.dtypes import (
ArrowDtype,
BaseMaskedDtype,
ExtensionDtype,
)
from pandas.core.dtypes.missing import isna

from pandas.core import (
Expand Down Expand Up @@ -501,6 +505,10 @@ def __mul__(self, other) -> Self:
f"Cannot multiply '{self.dtype}' by bool, explicitly cast to "
"integers instead"
)
if isinstance(other.dtype, (ArrowDtype, BaseMaskedDtype)):
# GH#58054
return NotImplemented

if len(other) != len(self) and not lib.is_np_dtype(other.dtype, "m"):
# Exclude timedelta64 here so we correctly raise TypeError
# for that instead of ValueError
Expand Down
25 changes: 25 additions & 0 deletions pandas/tests/arithmetic/test_timedelta64.py
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,31 @@ def test_td64arr_mul_bool_raises(self, dtype, box_with_array):
with pytest.raises(TypeError, match=msg2):
other * obj

@pytest.mark.parametrize(
"dtype",
[
"Int64",
"Float64",
pytest.param("int64[pyarrow]", marks=td.skip_if_no("pyarrow")),
],
)
def test_td64arr_mul_masked(self, dtype, box_with_array):
ser = Series(np.arange(5) * timedelta(hours=1))
obj = tm.box_expected(ser, box_with_array)

other = Series(np.arange(5), dtype=dtype)
other = tm.box_expected(other, box_with_array)

expected = Series([Timedelta(hours=n**2) for n in range(5)])
expected = tm.box_expected(expected, box_with_array)
if dtype == "int64[pyarrow]":
expected = expected.astype("duration[ns][pyarrow]")

result = obj * other
tm.assert_equal(result, expected)
result = other * obj
tm.assert_equal(result, expected)

# ------------------------------------------------------------------
# __div__, __rdiv__

Expand Down
Loading