diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 8eaf86b3d193f..f8f8a6f81d801 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -173,11 +173,11 @@ cpdef int64_t delta_to_nanoseconds(delta) except? -1: if is_tick_object(delta): return delta.nanos if isinstance(delta, _Timedelta): - delta = delta.value + return delta.value + if is_timedelta64_object(delta): return get_timedelta64_value(ensure_td64ns(delta)) - if is_integer_object(delta): - return delta + if PyDelta_Check(delta): try: return ( diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 7a7bad02fde72..e070f23b35315 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -1316,7 +1316,9 @@ def __add__(self, other): elif is_integer_dtype(other_dtype): if not is_period_dtype(self.dtype): raise integer_op_not_supported(self) - result = cast("PeriodArray", self)._addsub_int_array(other, operator.add) + result = cast("PeriodArray", self)._addsub_int_array_or_scalar( + other, operator.add + ) else: # Includes Categorical, other ExtensionArrays # For PeriodDtype, if self is a TimedeltaArray and other is a @@ -1376,7 +1378,9 @@ def __sub__(self, other): elif is_integer_dtype(other_dtype): if not is_period_dtype(self.dtype): raise integer_op_not_supported(self) - result = cast("PeriodArray", self)._addsub_int_array(other, operator.sub) + result = cast("PeriodArray", self)._addsub_int_array_or_scalar( + other, operator.sub + ) else: # Includes ExtensionArrays, float_dtype return NotImplemented diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 2368af0de1bf3..b2a8dfddc6b68 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -747,8 +747,8 @@ def _sub_period_array(self, other): new_values[mask] = NaT return new_values - def _addsub_int_array( - self, other: np.ndarray, op: Callable[[Any, Any], Any] + def _addsub_int_array_or_scalar( + self, other: np.ndarray | int, op: Callable[[Any, Any], Any] ) -> PeriodArray: """ Add or subtract array of integers; equivalent to applying @@ -756,7 +756,7 @@ def _addsub_int_array( Parameters ---------- - other : np.ndarray[integer-dtype] + other : np.ndarray[int64] or int op : {operator.add, operator.sub} Returns @@ -775,12 +775,7 @@ def _add_offset(self, other: BaseOffset): assert not isinstance(other, Tick) self._require_matching_freq(other, base=True) - - # Note: when calling parent class's _add_timedeltalike_scalar, - # it will call delta_to_nanoseconds(delta). Because delta here - # is an integer, delta_to_nanoseconds will return it unchanged. - result = super()._add_timedeltalike_scalar(other.n) - return type(self)(result, freq=self.freq) + return self._addsub_int_array_or_scalar(other.n, operator.add) def _add_timedeltalike_scalar(self, other): """ @@ -800,10 +795,8 @@ def _add_timedeltalike_scalar(self, other): # special handling for np.timedelta64("NaT"), avoid calling # _check_timedeltalike_freq_compat as that would raise TypeError other = self._check_timedeltalike_freq_compat(other) + other = np.timedelta64(other, "ns") - # Note: when calling parent class's _add_timedeltalike_scalar, - # it will call delta_to_nanoseconds(delta). Because delta here - # is an integer, delta_to_nanoseconds will return it unchanged. return super()._add_timedeltalike_scalar(other) def _add_timedelta_arraylike(self, other): @@ -828,7 +821,7 @@ def _add_timedelta_arraylike(self, other): # all-NaT TimedeltaIndex is equivalent to a single scalar td64 NaT return self + np.timedelta64("NaT") - ordinals = self._addsub_int_array(delta, operator.add).asi8 + ordinals = self._addsub_int_array_or_scalar(delta, operator.add).asi8 return type(self)(ordinals, dtype=self.dtype) def _check_timedeltalike_freq_compat(self, other): diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index a296ce130bbf5..fc7b122689ebb 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -272,7 +272,7 @@ def __new__( def values(self) -> np.ndarray: return np.asarray(self, dtype=object) - def _maybe_convert_timedelta(self, other): + def _maybe_convert_timedelta(self, other) -> int | npt.NDArray[np.int64]: """ Convert timedelta-like input to an integer multiple of self.freq diff --git a/pandas/tests/tslibs/test_timedeltas.py b/pandas/tests/tslibs/test_timedeltas.py index a0ec563d1f48f..7d7de7492a07b 100644 --- a/pandas/tests/tslibs/test_timedeltas.py +++ b/pandas/tests/tslibs/test_timedeltas.py @@ -30,9 +30,6 @@ 24 * 3600e9 + 111, ), # GH43764 (offsets.Nano(125), 125), - (1, 1), - (np.int64(2), 2), - (np.int32(3), 3), ], ) def test_delta_to_nanoseconds(obj, expected): @@ -46,6 +43,15 @@ def test_delta_to_nanoseconds_error(): with pytest.raises(TypeError, match=""): delta_to_nanoseconds(obj) + with pytest.raises(TypeError, match="float"): + delta_to_nanoseconds(1.5) + with pytest.raises(TypeError, match="int"): + delta_to_nanoseconds(1) + with pytest.raises(TypeError, match="int"): + delta_to_nanoseconds(np.int64(2)) + with pytest.raises(TypeError, match="int"): + delta_to_nanoseconds(np.int32(3)) + def test_huge_nanoseconds_overflow(): # GH 32402