|
22 | 22 | from pandas._libs.tslibs.offsets import (
|
23 | 23 | ApplyTypeError,
|
24 | 24 | as_datetime, _is_normalized,
|
25 |
| - _get_calendar, _to_dt64, _validate_business_time, |
| 25 | + _get_calendar, _to_dt64, |
26 | 26 | _determine_offset,
|
27 | 27 | apply_index_wraps,
|
28 | 28 | roll_yearday,
|
@@ -557,28 +557,31 @@ def get_str(td):
|
557 | 557 | def apply(self, other):
|
558 | 558 | if isinstance(other, datetime):
|
559 | 559 | n = self.n
|
| 560 | + wday = other.weekday() |
560 | 561 |
|
561 |
| - if n == 0 and other.weekday() > 4: |
562 |
| - n = 1 |
563 |
| - |
564 |
| - result = other |
565 |
| - |
566 |
| - # avoid slowness below |
567 |
| - if abs(n) > 5: |
568 |
| - k = n // 5 |
569 |
| - result = result + timedelta(7 * k) |
570 |
| - if n < 0 and result.weekday() > 4: |
571 |
| - n += 1 |
572 |
| - n -= 5 * k |
573 |
| - if n == 0 and result.weekday() > 4: |
574 |
| - n -= 1 |
| 562 | + # avoid slowness below by operating on weeks first |
| 563 | + weeks = n // 5 |
| 564 | + if n <= 0 and wday > 4: |
| 565 | + # roll forward |
| 566 | + n += 1 |
575 | 567 |
|
576 |
| - while n != 0: |
577 |
| - k = n // abs(n) |
578 |
| - result = result + timedelta(k) |
579 |
| - if result.weekday() < 5: |
580 |
| - n -= k |
| 568 | + n -= 5 * weeks |
| 569 | + |
| 570 | + # n is always >= 0 at this point |
| 571 | + if n == 0 and wday > 4: |
| 572 | + # roll back |
| 573 | + days = 4 - wday |
| 574 | + elif wday > 4: |
| 575 | + # roll forward |
| 576 | + days = (7 - wday) + (n - 1) |
| 577 | + elif wday + n <= 4: |
| 578 | + # shift by n days without leaving the current week |
| 579 | + days = n |
| 580 | + else: |
| 581 | + # shift by n days plus 2 to get past the weekend |
| 582 | + days = n + 2 |
581 | 583 |
|
| 584 | + result = other + timedelta(days=7 * weeks + days) |
582 | 585 | if self.offset:
|
583 | 586 | result = result + self.offset
|
584 | 587 | return result
|
@@ -614,8 +617,8 @@ class BusinessHourMixin(BusinessMixin):
|
614 | 617 | def __init__(self, start='09:00', end='17:00', offset=timedelta(0)):
|
615 | 618 | # must be validated here to equality check
|
616 | 619 | kwds = {'offset': offset}
|
617 |
| - self.start = kwds['start'] = _validate_business_time(start) |
618 |
| - self.end = kwds['end'] = _validate_business_time(end) |
| 620 | + self.start = kwds['start'] = liboffsets._validate_business_time(start) |
| 621 | + self.end = kwds['end'] = liboffsets._validate_business_time(end) |
619 | 622 | self.kwds.update(kwds)
|
620 | 623 | self._offset = offset
|
621 | 624 |
|
@@ -1092,21 +1095,20 @@ class CustomBusinessMonthBegin(_CustomBusinessMonth):
|
1092 | 1095 | @apply_wraps
|
1093 | 1096 | def apply(self, other):
|
1094 | 1097 | n = self.n
|
1095 |
| - dt_in = other |
1096 | 1098 |
|
1097 | 1099 | # First move to month offset
|
1098 |
| - cur_mbegin = self.m_offset.rollback(dt_in) |
| 1100 | + cur_mbegin = self.m_offset.rollback(other) |
1099 | 1101 |
|
1100 | 1102 | # Find this custom month offset
|
1101 | 1103 | cur_cmbegin = self.cbday.rollforward(cur_mbegin)
|
1102 | 1104 |
|
1103 | 1105 | # handle zero case. arbitrarily rollforward
|
1104 |
| - if n == 0 and dt_in != cur_cmbegin: |
| 1106 | + if n == 0 and other != cur_cmbegin: |
1105 | 1107 | n += 1
|
1106 | 1108 |
|
1107 |
| - if dt_in > cur_cmbegin and n <= -1: |
| 1109 | + if other > cur_cmbegin and n <= -1: |
1108 | 1110 | n += 1
|
1109 |
| - elif dt_in < cur_cmbegin and n >= 1: |
| 1111 | + elif other < cur_cmbegin and n >= 1: |
1110 | 1112 | n -= 1
|
1111 | 1113 |
|
1112 | 1114 | new = cur_mbegin + n * self.m_offset
|
@@ -1564,7 +1566,8 @@ class QuarterOffset(DateOffset):
|
1564 | 1566 | _from_name_startingMonth = None
|
1565 | 1567 | _adjust_dst = True
|
1566 | 1568 | # TODO: Consider combining QuarterOffset and YearOffset __init__ at some
|
1567 |
| - # point |
| 1569 | + # point. Also apply_index, onOffset, rule_code if |
| 1570 | + # startingMonth vs month attr names are resolved |
1568 | 1571 |
|
1569 | 1572 | def __init__(self, n=1, normalize=False, startingMonth=None):
|
1570 | 1573 | self.n = self._validate_n(n)
|
@@ -1613,8 +1616,8 @@ def apply(self, other):
|
1613 | 1616 | def onOffset(self, dt):
|
1614 | 1617 | if self.normalize and not _is_normalized(dt):
|
1615 | 1618 | return False
|
1616 |
| - modMonth = (dt.month - self.startingMonth) % 3 |
1617 |
| - return modMonth == 0 and dt.day == self._get_offset_day(dt) |
| 1619 | + mod_month = (dt.month - self.startingMonth) % 3 |
| 1620 | + return mod_month == 0 and dt.day == self._get_offset_day(dt) |
1618 | 1621 |
|
1619 | 1622 | @apply_index_wraps
|
1620 | 1623 | def apply_index(self, dtindex):
|
@@ -2158,6 +2161,7 @@ def apply(self, other):
|
2158 | 2161 | n -= 1
|
2159 | 2162 | elif n < 0 and other > current_easter:
|
2160 | 2163 | n += 1
|
| 2164 | + # TODO: Why does this handle the 0 case the opposite of others? |
2161 | 2165 |
|
2162 | 2166 | # NOTE: easter returns a datetime.date so we have to convert to type of
|
2163 | 2167 | # other
|
|
0 commit comments