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 @@ -895,6 +895,7 @@ Timedelta
- Accuracy improvement in :meth:`Timedelta.to_pytimedelta` to round microseconds consistently for large nanosecond based Timedelta (:issue:`57841`)
- 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`)

Timezones
^^^^^^^^^
Expand Down
12 changes: 12 additions & 0 deletions pandas/core/arrays/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ def _add_offset(self, other):
@unpack_zerodim_and_defer("__mul__")
def __mul__(self, other) -> Self:
if is_scalar(other):
if lib.is_bool(other):
raise TypeError(
f"Cannot multiply '{self.dtype}' by bool, explicitly cast to "
"integers instead"
)
# numpy will accept float and int, raise TypeError for others
result = self._ndarray * other
if result.dtype.kind != "m":
Expand All @@ -489,6 +494,13 @@ def __mul__(self, other) -> Self:
if not hasattr(other, "dtype"):
# list, tuple
other = np.array(other)

if other.dtype.kind == "b":
# GH#58054
raise TypeError(
f"Cannot multiply '{self.dtype}' by bool, explicitly cast to "
"integers instead"
)
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
46 changes: 46 additions & 0 deletions pandas/tests/arithmetic/test_timedelta64.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from pandas._libs.tslibs import timezones
from pandas.compat import WASM
from pandas.errors import OutOfBoundsDatetime
import pandas.util._test_decorators as td

import pandas as pd
from pandas import (
Expand Down Expand Up @@ -1556,6 +1557,51 @@ def test_tdi_rmul_arraylike(self, other, box_with_array):
commute = tdi * other
tm.assert_equal(commute, expected)

def test_td64arr_mul_bool_scalar_raises(self, box_with_array):
# GH#58054
ser = Series(np.arange(5) * timedelta(hours=1))
obj = tm.box_expected(ser, box_with_array)

msg = r"Cannot multiply 'timedelta64\[ns\]' by bool"
with pytest.raises(TypeError, match=msg):
True * obj
with pytest.raises(TypeError, match=msg):
obj * True
with pytest.raises(TypeError, match=msg):
np.True_ * obj
with pytest.raises(TypeError, match=msg):
obj * np.True_

@pytest.mark.parametrize(
"dtype",
[
bool,
"boolean",
pytest.param("bool[pyarrow]", marks=td.skip_if_no("pyarrow")),
],
)
def test_td64arr_mul_bool_raises(self, dtype, box_with_array):
# GH#58054
ser = Series(np.arange(5) * timedelta(hours=1))
obj = tm.box_expected(ser, box_with_array)

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

msg = r"Cannot multiply 'timedelta64\[ns\]' by bool"
with pytest.raises(TypeError, match=msg):
obj * other

msg2 = msg.replace("rmul", "mul")
if dtype == "bool[pyarrow]":
# We go through ArrowEA.__mul__ which gives a different message
msg2 = (
r"operation 'mul' not supported for dtype 'bool\[pyarrow\]' "
r"with dtype 'timedelta64\[ns\]'"
)
with pytest.raises(TypeError, match=msg2):
other * obj

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

Expand Down
Loading