From 4dbb5e1cac74897d0fa6f5d2f3beb80111ba5476 Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 14 Jun 2020 13:35:19 -0700 Subject: [PATCH 1/2] REF: de-duplicate --- pandas/_libs/tslibs/offsets.pyx | 286 ++++++++++---------------------- 1 file changed, 86 insertions(+), 200 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 9e6356b55dcec..6c485bc90cd15 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -3740,131 +3740,17 @@ cdef shift_quarters( out : ndarray[int64_t] """ cdef: - Py_ssize_t i - npy_datetimestruct dts - int count = len(dtindex) - int months_to_roll, months_since, n, compare_day + Py_ssize_t count = len(dtindex) int64_t[:] out = np.empty(count, dtype="int64") if day_opt == "start": - with nogil: - for i in range(count): - if dtindex[i] == NPY_NAT: - out[i] = NPY_NAT - continue - - dt64_to_dtstruct(dtindex[i], &dts) - n = quarters - - months_since = (dts.month - q1start_month) % modby - compare_day = get_day_of_month(&dts, day_opt) - - # offset semantics - if on the anchor point and going backwards - # shift to next - if n <= 0 and (months_since != 0 or - (months_since == 0 and dts.day > compare_day)): - # make sure to roll forward, so negate - n += 1 - elif n > 0 and (months_since == 0 and dts.day < compare_day): - # pretend to roll back if on same month but - # before compare_day - n -= 1 - - dts.year = year_add_months(dts, modby * n - months_since) - dts.month = month_add_months(dts, modby * n - months_since) - dts.day = get_day_of_month(&dts, day_opt) - - out[i] = dtstruct_to_dt64(&dts) - + _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) elif day_opt == "end": - with nogil: - for i in range(count): - if dtindex[i] == NPY_NAT: - out[i] = NPY_NAT - continue - - dt64_to_dtstruct(dtindex[i], &dts) - n = quarters - - months_since = (dts.month - q1start_month) % modby - compare_day = get_day_of_month(&dts, day_opt) - - if n <= 0 and (months_since != 0 or - (months_since == 0 and dts.day > compare_day)): - # make sure to roll forward, so negate - n += 1 - elif n > 0 and (months_since == 0 and dts.day < compare_day): - # pretend to roll back if on same month but - # before compare_day - n -= 1 - - dts.year = year_add_months(dts, modby * n - months_since) - dts.month = month_add_months(dts, modby * n - months_since) - dts.day = get_day_of_month(&dts, day_opt) - - out[i] = dtstruct_to_dt64(&dts) - + _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) elif day_opt == "business_start": - with nogil: - for i in range(count): - if dtindex[i] == NPY_NAT: - out[i] = NPY_NAT - continue - - dt64_to_dtstruct(dtindex[i], &dts) - n = quarters - - months_since = (dts.month - q1start_month) % modby - # compare_day is only relevant for comparison in the case - # where months_since == 0. - compare_day = get_day_of_month(&dts, day_opt) - - if n <= 0 and (months_since != 0 or - (months_since == 0 and dts.day > compare_day)): - # make sure to roll forward, so negate - n += 1 - elif n > 0 and (months_since == 0 and dts.day < compare_day): - # pretend to roll back if on same month but - # before compare_day - n -= 1 - - dts.year = year_add_months(dts, modby * n - months_since) - dts.month = month_add_months(dts, modby * n - months_since) - - dts.day = get_day_of_month(&dts, day_opt) - - out[i] = dtstruct_to_dt64(&dts) - + _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) elif day_opt == "business_end": - with nogil: - for i in range(count): - if dtindex[i] == NPY_NAT: - out[i] = NPY_NAT - continue - - dt64_to_dtstruct(dtindex[i], &dts) - n = quarters - - months_since = (dts.month - q1start_month) % modby - # compare_day is only relevant for comparison in the case - # where months_since == 0. - compare_day = get_day_of_month(&dts, day_opt) - - if n <= 0 and (months_since != 0 or - (months_since == 0 and dts.day > compare_day)): - # make sure to roll forward, so negate - n += 1 - elif n > 0 and (months_since == 0 and dts.day < compare_day): - # pretend to roll back if on same month but - # before compare_day - n -= 1 - - dts.year = year_add_months(dts, modby * n - months_since) - dts.month = month_add_months(dts, modby * n - months_since) - - dts.day = get_day_of_month(&dts, day_opt) - - out[i] = dtstruct_to_dt64(&dts) + _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) else: raise ValueError("day must be None, 'start', 'end', " @@ -3889,7 +3775,6 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None): Py_ssize_t i npy_datetimestruct dts int count = len(dtindex) - int months_to_roll int64_t[:] out = np.empty(count, dtype="int64") if day_opt is None: @@ -3906,97 +3791,98 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None): dts.day = min(dts.day, get_days_in_month(dts.year, dts.month)) out[i] = dtstruct_to_dt64(&dts) elif day_opt == "start": - with nogil: - for i in range(count): - if dtindex[i] == NPY_NAT: - out[i] = NPY_NAT - continue - - dt64_to_dtstruct(dtindex[i], &dts) - months_to_roll = months - compare_day = get_day_of_month(&dts, day_opt) - - # offset semantics - if on the anchor point and going backwards - # shift to next - months_to_roll = roll_convention(dts.day, months_to_roll, - compare_day) - - dts.year = year_add_months(dts, months_to_roll) - dts.month = month_add_months(dts, months_to_roll) - dts.day = get_day_of_month(&dts, day_opt) - - out[i] = dtstruct_to_dt64(&dts) + _shift_months(dtindex, out, count, months, day_opt) elif day_opt == "end": - with nogil: - for i in range(count): - if dtindex[i] == NPY_NAT: - out[i] = NPY_NAT - continue + _shift_months(dtindex, out, count, months, day_opt) + elif day_opt == "business_start": + _shift_months(dtindex, out, count, months, day_opt) + elif day_opt == "business_end": + _shift_months(dtindex, out, count, months, day_opt) - dt64_to_dtstruct(dtindex[i], &dts) - months_to_roll = months - compare_day = get_day_of_month(&dts, day_opt) + else: + raise ValueError("day must be None, 'start', 'end', " + "'business_start', or 'business_end'") - # similar semantics - when adding shift forward by one - # month if already at an end of month - months_to_roll = roll_convention(dts.day, months_to_roll, - compare_day) + return np.asarray(out) - dts.year = year_add_months(dts, months_to_roll) - dts.month = month_add_months(dts, months_to_roll) - dts.day = get_day_of_month(&dts, day_opt) - out[i] = dtstruct_to_dt64(&dts) +@cython.wraparound(False) +@cython.boundscheck(False) +cdef inline void _shift_months(const int64_t[:] dtindex, + int64_t[:] out, + Py_ssize_t count, + int months, + str day_opt) nogil: + """See shift_months.__doc__""" + cdef: + Py_ssize_t i + int months_to_roll, compare_day + npy_datetimestruct dts - elif day_opt == "business_start": - with nogil: - for i in range(count): - if dtindex[i] == NPY_NAT: - out[i] = NPY_NAT - continue + for i in range(count): + if dtindex[i] == NPY_NAT: + out[i] = NPY_NAT + continue - dt64_to_dtstruct(dtindex[i], &dts) - months_to_roll = months - compare_day = get_day_of_month(&dts, day_opt) + dt64_to_dtstruct(dtindex[i], &dts) + months_to_roll = months + compare_day = get_day_of_month(&dts, day_opt) - months_to_roll = roll_convention(dts.day, months_to_roll, - compare_day) + months_to_roll = roll_convention(dts.day, months_to_roll, + compare_day) - dts.year = year_add_months(dts, months_to_roll) - dts.month = month_add_months(dts, months_to_roll) + dts.year = year_add_months(dts, months_to_roll) + dts.month = month_add_months(dts, months_to_roll) + dts.day = get_day_of_month(&dts, day_opt) - dts.day = get_day_of_month(&dts, day_opt) - out[i] = dtstruct_to_dt64(&dts) + out[i] = dtstruct_to_dt64(&dts) - elif day_opt == "business_end": - with nogil: - for i in range(count): - if dtindex[i] == NPY_NAT: - out[i] = NPY_NAT - continue - dt64_to_dtstruct(dtindex[i], &dts) - months_to_roll = months - compare_day = get_day_of_month(&dts, day_opt) +@cython.wraparound(False) +@cython.boundscheck(False) +cdef inline void _shift_quarters(const int64_t[:] dtindex, + int64_t[:] out, + Py_ssize_t count, + int quarters, + int q1start_month, + str day_opt, + int modby) nogil: + """See shift_quarters.__doc__""" + cdef: + Py_ssize_t i + int months_since, compare_day, n + npy_datetimestruct dts - months_to_roll = roll_convention(dts.day, months_to_roll, - compare_day) + for i in range(count): + if dtindex[i] == NPY_NAT: + out[i] = NPY_NAT + continue - dts.year = year_add_months(dts, months_to_roll) - dts.month = month_add_months(dts, months_to_roll) + dt64_to_dtstruct(dtindex[i], &dts) + n = quarters - dts.day = get_day_of_month(&dts, day_opt) - out[i] = dtstruct_to_dt64(&dts) + months_since = (dts.month - q1start_month) % modby + compare_day = get_day_of_month(&dts, day_opt) - else: - raise ValueError("day must be None, 'start', 'end', " - "'business_start', or 'business_end'") + # offset semantics - if on the anchor point and going backwards + # shift to next + if n <= 0 and (months_since != 0 or + (months_since == 0 and dts.day > compare_day)): + # make sure to roll forward, so negate + n += 1 + elif n > 0 and (months_since == 0 and dts.day < compare_day): + # pretend to roll back if on same month but + # before compare_day + n -= 1 - return np.asarray(out) + dts.year = year_add_months(dts, modby * n - months_since) + dts.month = month_add_months(dts, modby * n - months_since) + dts.day = get_day_of_month(&dts, day_opt) + out[i] = dtstruct_to_dt64(&dts) -def shift_month(stamp: datetime, months: int, - day_opt: object=None) -> datetime: + +def shift_month(stamp: datetime, months: int, day_opt: object=None) -> datetime: """ Given a datetime (or Timestamp) `stamp`, an integer `months` and an option `day_opt`, return a new datetimelike that many months later, @@ -4038,14 +3924,14 @@ def shift_month(stamp: datetime, months: int, if day_opt is None: days_in_month = get_days_in_month(year, month) day = min(stamp.day, days_in_month) - elif day_opt == 'start': + elif day_opt == "start": day = 1 - elif day_opt == 'end': + elif day_opt == "end": day = get_days_in_month(year, month) - elif day_opt == 'business_start': + elif day_opt == "business_start": # first business day of month day = get_firstbday(year, month) - elif day_opt == 'business_end': + elif day_opt == "business_end": # last business day of month day = get_lastbday(year, month) elif is_integer_object(day_opt): @@ -4086,15 +3972,15 @@ cdef inline int get_day_of_month(npy_datetimestruct* dts, day_opt) nogil except? cdef: int days_in_month - if day_opt == 'start': + if day_opt == "start": return 1 - elif day_opt == 'end': + elif day_opt == "end": days_in_month = get_days_in_month(dts.year, dts.month) return days_in_month - elif day_opt == 'business_start': + elif day_opt == "business_start": # first business day of month return get_firstbday(dts.year, dts.month) - elif day_opt == 'business_end': + elif day_opt == "business_end": # last business day of month return get_lastbday(dts.year, dts.month) elif day_opt is not None: From fa8ca341411105aa0de8d9d0feb58636ca8f3069 Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 14 Jun 2020 14:56:35 -0700 Subject: [PATCH 2/2] REF: de-duplicate --- pandas/_libs/tslibs/offsets.pyx | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 237d8a3987ec7..dae1d9997dac2 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -3743,19 +3743,11 @@ cdef shift_quarters( Py_ssize_t count = len(dtindex) int64_t[:] out = np.empty(count, dtype="int64") - if day_opt == "start": - _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) - elif day_opt == "end": - _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) - elif day_opt == "business_start": - _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) - elif day_opt == "business_end": - _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) - - else: + if day_opt not in ["start", "end", "business_start", "business_end"]: raise ValueError("day must be None, 'start', 'end', " "'business_start', or 'business_end'") + _shift_quarters(dtindex, out, count, quarters, q1start_month, day_opt, modby) return np.asarray(out) @@ -3790,13 +3782,7 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None): dts.day = min(dts.day, get_days_in_month(dts.year, dts.month)) out[i] = dtstruct_to_dt64(&dts) - elif day_opt == "start": - _shift_months(dtindex, out, count, months, day_opt) - elif day_opt == "end": - _shift_months(dtindex, out, count, months, day_opt) - elif day_opt == "business_start": - _shift_months(dtindex, out, count, months, day_opt) - elif day_opt == "business_end": + elif day_opt in ["start", "end", "business_start", "business_end"]: _shift_months(dtindex, out, count, months, day_opt) else: