diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 973fdbdc4014c..16cb771d0f642 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -5,8 +5,7 @@ import numpy as np -from pandas._libs import NaT, NaTType, Timestamp, algos, iNaT, lib -from pandas._libs.tslibs.period import DIFFERENT_FREQ, IncompatibleFrequency, Period +from pandas._libs import NaT, NaTType, Period, Timestamp, algos, iNaT, lib from pandas._libs.tslibs.timedeltas import delta_to_nanoseconds from pandas._libs.tslibs.timestamps import ( RoundTo, @@ -740,7 +739,7 @@ def _validate_shift_value(self, fill_value): # only warn if we're not going to raise if self._scalar_type is Period and lib.is_integer(fill_value): # kludge for #31971 since Period(integer) tries to cast to str - new_fill = Period._from_ordinal(fill_value, freq=self.freq) + new_fill = Period._from_ordinal(fill_value, freq=self.dtype.freq) else: new_fill = self._scalar_type(fill_value) @@ -1091,7 +1090,7 @@ def _resolution(self): return frequencies.Resolution.get_reso_from_freq(self.freqstr) @property # NB: override with cache_readonly in immutable subclasses - def resolution(self): + def resolution(self) -> str: """ Returns day, hour, minute, second, millisecond or microsecond """ @@ -1274,41 +1273,11 @@ def _sub_nat(self): return result.view("timedelta64[ns]") def _sub_period_array(self, other): - """ - Subtract a Period Array/Index from self. This is only valid if self - is itself a Period Array/Index, raises otherwise. Both objects must - have the same frequency. - - Parameters - ---------- - other : PeriodIndex or PeriodArray - - Returns - ------- - result : np.ndarray[object] - Array of DateOffset objects; nulls represented by NaT. - """ - if not is_period_dtype(self.dtype): - raise TypeError( - f"cannot subtract {other.dtype}-dtype from {type(self).__name__}" - ) - - if self.freq != other.freq: - msg = DIFFERENT_FREQ.format( - cls=type(self).__name__, own_freq=self.freqstr, other_freq=other.freqstr - ) - raise IncompatibleFrequency(msg) - - new_values = checked_add_with_arr( - self.asi8, -other.asi8, arr_mask=self._isnan, b_mask=other._isnan + # Overridden by PeriodArray + raise TypeError( + f"cannot subtract {other.dtype}-dtype from {type(self).__name__}" ) - new_values = np.array([self.freq.base * x for x in new_values]) - if self._hasnans or other._hasnans: - mask = (self._isnan) | (other._isnan) - new_values[mask] = NaT - return new_values - def _addsub_object_array(self, other: np.ndarray, op): """ Add or subtract array-like of DateOffset objects diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 8be714820d18b..80a78409a3036 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -604,6 +604,37 @@ def _sub_period(self, other): return new_data + def _sub_period_array(self, other): + """ + Subtract a Period Array/Index from self. This is only valid if self + is itself a Period Array/Index, raises otherwise. Both objects must + have the same frequency. + + Parameters + ---------- + other : PeriodIndex or PeriodArray + + Returns + ------- + result : np.ndarray[object] + Array of DateOffset objects; nulls represented by NaT. + """ + if self.freq != other.freq: + msg = DIFFERENT_FREQ.format( + cls=type(self).__name__, own_freq=self.freqstr, other_freq=other.freqstr + ) + raise IncompatibleFrequency(msg) + + new_values = algos.checked_add_with_arr( + self.asi8, -other.asi8, arr_mask=self._isnan, b_mask=other._isnan + ) + + new_values = np.array([self.freq.base * x for x in new_values]) + if self._hasnans or other._hasnans: + mask = (self._isnan) | (other._isnan) + new_values[mask] = NaT + return new_values + def _addsub_int_array( self, other: np.ndarray, op: Callable[[Any, Any], Any], ) -> "PeriodArray":