From 830789c56a470be93fd782bcf4f006e3d7e07427 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 8 Jan 2018 18:09:47 -0800 Subject: [PATCH 1/4] simplify CBMonth.apply to remove roll_monthday --- pandas/_libs/tslibs/offsets.pyx | 23 -------- .../tests/tseries/offsets/test_liboffsets.py | 16 ------ pandas/tseries/offsets.py | 53 +++++++++---------- 3 files changed, 26 insertions(+), 66 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 585c904a601ed..1dea41801003d 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -847,29 +847,6 @@ cpdef int roll_convention(int other, int n, int compare): return n -cpdef int roll_monthday(datetime other, int n, datetime compare): - """ - Possibly increment or decrement the number of periods to shift - based on rollforward/rollbackward conventions. - - Parameters - ---------- - other : datetime - n : number of periods to increment, before adjusting for rolling - compare : datetime - - Returns - ------- - n : int number of periods to increment - """ - if n > 0 and other < compare: - n -= 1 - elif n <= 0 and other > compare: - # as if rolled forward already - n += 1 - return n - - cpdef int roll_qtrday(datetime other, int n, int month, object day_opt, int modby=3) except? -1: """ diff --git a/pandas/tests/tseries/offsets/test_liboffsets.py b/pandas/tests/tseries/offsets/test_liboffsets.py index 1e0ecc39084eb..a31a79d2f68ed 100644 --- a/pandas/tests/tseries/offsets/test_liboffsets.py +++ b/pandas/tests/tseries/offsets/test_liboffsets.py @@ -156,22 +156,6 @@ def test_roll_qtrday(): assert roll_qtrday(other, n, month, 'business_end', modby=3) == n -def test_roll_monthday(): - other = Timestamp('2017-12-29', tz='US/Pacific') - before = Timestamp('2017-12-01', tz='US/Pacific') - after = Timestamp('2017-12-31', tz='US/Pacific') - - n = 42 - assert liboffsets.roll_monthday(other, n, other) == n - assert liboffsets.roll_monthday(other, n, before) == n - assert liboffsets.roll_monthday(other, n, after) == n - 1 - - n = -4 - assert liboffsets.roll_monthday(other, n, other) == n - assert liboffsets.roll_monthday(other, n, before) == n + 1 - assert liboffsets.roll_monthday(other, n, after) == n - - def test_roll_convention(): other = 29 before = 1 diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 7c5fe2f0314e4..0136d4f8adc98 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1040,54 +1040,53 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', @cache_readonly def cbday(self): + cbday = CustomBusinessDay(n=self.n, normalize=False, **self.kwds) + + # Define default roll function to be called in apply method + if self._prefix.endswith('S'): + # MonthBegin + cbday.roll_func = cbday.rollforward + else: + # MonthEnd + cbday.roll_func = cbday.rollback kwds = self.kwds - return CustomBusinessDay(n=self.n, normalize=self.normalize, **kwds) + return cbday @cache_readonly def m_offset(self): if self._prefix.endswith('S'): - # MonthBegin: - return MonthBegin(n=1, normalize=self.normalize) + # MonthBegin + moff = MonthBegin(n=1, normalize=False) + moff.roll_func = moff.rollback else: # MonthEnd - return MonthEnd(n=1, normalize=self.normalize) - - -class CustomBusinessMonthEnd(_CustomBusinessMonth): - __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'end') - _prefix = 'CBM' + moff = MonthEnd(n=1, normalize=False) + moff.roll_func = moff.rollforward + return moff @apply_wraps def apply(self, other): # First move to month offset - cur_mend = self.m_offset.rollforward(other) + cur_month_offset_date = self.m_offset.roll_func(other) # Find this custom month offset - compare_date = self.cbday.rollback(cur_mend) - n = liboffsets.roll_monthday(other, self.n, compare_date) + compare_date = self.cbday.roll_func(cur_month_offset_date) + n = liboffsets.roll_convention(other.day, self.n, compare_date.day) - new = cur_mend + n * self.m_offset - result = self.cbday.rollback(new) + new = cur_month_offset_date + n * self.m_offset + result = self.cbday.roll_func(new) return result +class CustomBusinessMonthEnd(_CustomBusinessMonth): + __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'end') + _prefix = 'CBM' + + class CustomBusinessMonthBegin(_CustomBusinessMonth): __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'beginning') _prefix = 'CBMS' - @apply_wraps - def apply(self, other): - # First move to month offset - cur_mbegin = self.m_offset.rollback(other) - - # Find this custom month offset - compare_date = self.cbday.rollforward(cur_mbegin) - n = liboffsets.roll_monthday(other, self.n, compare_date) - - new = cur_mbegin + n * self.m_offset - result = self.cbday.rollforward(new) - return result - # --------------------------------------------------------------------- # Semi-Month Based Offset Classes From ad4a8c3d99c433afea022c11c77fe8a8f3a0c3df Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 8 Jan 2018 19:47:34 -0800 Subject: [PATCH 2/4] flake8 cleanup --- pandas/tseries/offsets.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 0136d4f8adc98..4c2b096639378 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1049,7 +1049,6 @@ def cbday(self): else: # MonthEnd cbday.roll_func = cbday.rollback - kwds = self.kwds return cbday @cache_readonly From 2c79b38baf46a3bc6664fbdae2d736a3e13575c4 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 9 Jan 2018 08:17:52 -0800 Subject: [PATCH 3/4] requested refactor --- pandas/tseries/offsets.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 4c2b096639378..0b94f0930f950 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1039,41 +1039,49 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', _CustomMixin.__init__(self, weekmask, holidays, calendar) @cache_readonly - def cbday(self): + def cbday_roll(self): cbday = CustomBusinessDay(n=self.n, normalize=False, **self.kwds) # Define default roll function to be called in apply method if self._prefix.endswith('S'): # MonthBegin - cbday.roll_func = cbday.rollforward + roll_func = cbday.rollforward else: # MonthEnd - cbday.roll_func = cbday.rollback - return cbday + roll_func = cbday.rollback + return roll_func @cache_readonly def m_offset(self): if self._prefix.endswith('S'): # MonthBegin moff = MonthBegin(n=1, normalize=False) - moff.roll_func = moff.rollback else: # MonthEnd moff = MonthEnd(n=1, normalize=False) - moff.roll_func = moff.rollforward return moff + @cache_readonly + def month_roll(self): + if self._prefix.endswith('S'): + # MonthBegin + roll_func = self.m_offset.rollback + else: + # MonthEnd + roll_func = self.m_offset.rollforward + return roll_func + @apply_wraps def apply(self, other): # First move to month offset - cur_month_offset_date = self.m_offset.roll_func(other) + cur_month_offset_date = self.month_roll(other) # Find this custom month offset - compare_date = self.cbday.roll_func(cur_month_offset_date) + compare_date = self.cbday_roll(cur_month_offset_date) n = liboffsets.roll_convention(other.day, self.n, compare_date.day) new = cur_month_offset_date + n * self.m_offset - result = self.cbday.roll_func(new) + result = self.cbday_roll(new) return result From 4ee7c82c11ba0efda13a583784b25875863658f9 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 9 Jan 2018 16:58:51 -0800 Subject: [PATCH 4/4] docstrings --- pandas/tseries/offsets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 0b94f0930f950..3c842affd44b7 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1040,9 +1040,9 @@ def __init__(self, n=1, normalize=False, weekmask='Mon Tue Wed Thu Fri', @cache_readonly def cbday_roll(self): + """Define default roll function to be called in apply method""" cbday = CustomBusinessDay(n=self.n, normalize=False, **self.kwds) - # Define default roll function to be called in apply method if self._prefix.endswith('S'): # MonthBegin roll_func = cbday.rollforward @@ -1063,6 +1063,7 @@ def m_offset(self): @cache_readonly def month_roll(self): + """Define default roll function to be called in apply method""" if self._prefix.endswith('S'): # MonthBegin roll_func = self.m_offset.rollback