Skip to content

Commit 36a86d2

Browse files
authored
REF: make DateOffset apply_index methods operate on ndarrays where feasible (#34612)
1 parent f5bea29 commit 36a86d2

File tree

1 file changed

+26
-21
lines changed

1 file changed

+26
-21
lines changed

pandas/_libs/tslibs/offsets.pyx

+26-21
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ from pandas._libs.tslibs.timezones cimport utc_pytz as UTC
4747
from pandas._libs.tslibs.tzconversion cimport tz_convert_single
4848

4949
from .dtypes cimport PeriodDtypeCode
50+
from .fields import get_start_end_field
5051
from .timedeltas cimport delta_to_nanoseconds
5152
from .timedeltas import Timedelta
5253
from .timestamps cimport _Timestamp
@@ -2291,7 +2292,7 @@ cdef class SemiMonthOffset(SingleConstructorOffset):
22912292
after_day_of_month = days_from_start > delta
22922293

22932294
# determine the correct n for each date in dtindex
2294-
roll = self._get_roll(dtindex, before_day_of_month, after_day_of_month)
2295+
roll = self._get_roll(i8other, before_day_of_month, after_day_of_month)
22952296

22962297
# isolate the time since it will be striped away one the next line
22972298
time = (i8other % DAY_NANOS).view("timedelta64[ns]")
@@ -2304,24 +2305,26 @@ cdef class SemiMonthOffset(SingleConstructorOffset):
23042305

23052306
shifted = asper._addsub_int_array(roll // 2, operator.add)
23062307
dtindex = type(dti)(shifted.to_timestamp())
2308+
dt64other = np.asarray(dtindex)
23072309

23082310
# apply the correct day
2309-
dtindex = self._apply_index_days(dtindex, roll)
2311+
dt64result = self._apply_index_days(dt64other, roll)
23102312

2311-
return dtindex + time
2313+
return dt64result + time
23122314

2313-
def _get_roll(self, dtindex, before_day_of_month, after_day_of_month):
2315+
def _get_roll(self, i8other, before_day_of_month, after_day_of_month):
23142316
"""
23152317
Return an array with the correct n for each date in dtindex.
23162318
23172319
The roll array is based on the fact that dtindex gets rolled back to
23182320
the first day of the month.
23192321
"""
2322+
# before_day_of_month and after_day_of_month are ndarray[bool]
23202323
raise NotImplementedError
23212324

2322-
def _apply_index_days(self, dtindex, roll):
2325+
def _apply_index_days(self, dt64other, roll):
23232326
"""
2324-
Apply the correct day for each date in dtindex.
2327+
Apply the correct day for each date in dt64other.
23252328
"""
23262329
raise NotImplementedError
23272330

@@ -2352,9 +2355,10 @@ cdef class SemiMonthEnd(SemiMonthOffset):
23522355
day = 31 if n % 2 else self.day_of_month
23532356
return shift_month(other, months, day)
23542357

2355-
def _get_roll(self, dtindex, before_day_of_month, after_day_of_month):
2358+
def _get_roll(self, i8other, before_day_of_month, after_day_of_month):
2359+
# before_day_of_month and after_day_of_month are ndarray[bool]
23562360
n = self.n
2357-
is_month_end = dtindex.is_month_end
2361+
is_month_end = get_start_end_field(i8other, "is_month_end")
23582362
if n > 0:
23592363
roll_end = np.where(is_month_end, 1, 0)
23602364
roll_before = np.where(before_day_of_month, n, n + 1)
@@ -2367,22 +2371,22 @@ cdef class SemiMonthEnd(SemiMonthOffset):
23672371
roll = np.where(after_day_of_month, n + 2, n + 1)
23682372
return roll
23692373

2370-
def _apply_index_days(self, dtindex, roll):
2374+
def _apply_index_days(self, dt64other, roll):
23712375
"""
2372-
Add days portion of offset to DatetimeIndex dtindex.
2376+
Add days portion of offset to dt64other.
23732377
23742378
Parameters
23752379
----------
2376-
dtindex : DatetimeIndex
2380+
dt64other : ndarray[datetime64[ns]]
23772381
roll : ndarray[int64_t]
23782382
23792383
Returns
23802384
-------
2381-
result : DatetimeIndex
2385+
ndarray[datetime64[ns]]
23822386
"""
23832387
nanos = (roll % 2) * Timedelta(days=self.day_of_month).value
2384-
dtindex += nanos.astype("timedelta64[ns]")
2385-
return dtindex + Timedelta(days=-1)
2388+
dt64other += nanos.astype("timedelta64[ns]")
2389+
return dt64other + Timedelta(days=-1)
23862390

23872391

23882392
cdef class SemiMonthBegin(SemiMonthOffset):
@@ -2409,9 +2413,10 @@ cdef class SemiMonthBegin(SemiMonthOffset):
24092413
day = 1 if n % 2 else self.day_of_month
24102414
return shift_month(other, months, day)
24112415

2412-
def _get_roll(self, dtindex, before_day_of_month, after_day_of_month):
2416+
def _get_roll(self, i8other, before_day_of_month, after_day_of_month):
2417+
# before_day_of_month and after_day_of_month are ndarray[bool]
24132418
n = self.n
2414-
is_month_start = dtindex.is_month_start
2419+
is_month_start = get_start_end_field(i8other, "is_month_start")
24152420
if n > 0:
24162421
roll = np.where(before_day_of_month, n, n + 1)
24172422
elif n == 0:
@@ -2424,21 +2429,21 @@ cdef class SemiMonthBegin(SemiMonthOffset):
24242429
roll = roll_after + roll_start
24252430
return roll
24262431

2427-
def _apply_index_days(self, dtindex, roll):
2432+
def _apply_index_days(self, dt64other, roll):
24282433
"""
2429-
Add days portion of offset to DatetimeIndex dtindex.
2434+
Add days portion of offset to dt64other.
24302435
24312436
Parameters
24322437
----------
2433-
dtindex : DatetimeIndex
2438+
dt64other : ndarray[datetime64[ns]]
24342439
roll : ndarray[int64_t]
24352440
24362441
Returns
24372442
-------
2438-
result : DatetimeIndex
2443+
ndarray[datetime64[ns]]
24392444
"""
24402445
nanos = (roll % 2) * Timedelta(days=self.day_of_month - 1).value
2441-
return dtindex + nanos.astype("timedelta64[ns]")
2446+
return dt64other + nanos.astype("timedelta64[ns]")
24422447

24432448

24442449
# ---------------------------------------------------------------------

0 commit comments

Comments
 (0)