From a944a271f2e27253a1e1ee9b812fa3dc1b8b0dde Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Wed, 17 Feb 2021 17:39:19 +0100 Subject: [PATCH 01/64] Update offsets.pyx Fixes to year, quarter and month offsets. --- pandas/_libs/tslibs/offsets.pyx | 269 ++++++++++++++++++++------------ 1 file changed, 166 insertions(+), 103 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 2d4704ad3bda6..14dac644442a1 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1838,12 +1838,11 @@ cdef class YearOffset(SingleConstructorOffset): """ DateOffset that just needs a month. """ + _attributes = tuple(["n", "normalize", "month"]) - # _default_month: int # FIXME: python annotation here breaks things - cdef readonly: - int month + int month, _default_month, _period_dtype_code def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) @@ -1853,6 +1852,8 @@ cdef class YearOffset(SingleConstructorOffset): if month < 1 or month > 12: raise ValueError("Month must go from 1 to 12") + + self._period_dtype_code = PeriodDtypeCode.A + self.month % 12 cpdef __setstate__(self, state): self.month = state.pop("month") @@ -1865,8 +1866,11 @@ cdef class YearOffset(SingleConstructorOffset): kwargs = {} if suffix: kwargs["month"] = MONTH_TO_CAL_NUM[suffix] + else: + if cls._default_month is not None: + kwargs["month"] = cls._default_month return cls(**kwargs) - + @property def rule_code(self) -> str: month = MONTH_ALIASES[self.month] @@ -1902,40 +1906,58 @@ cdef class YearOffset(SingleConstructorOffset): ) return shifted - -cdef class BYearEnd(YearOffset): + +cdef class YearBegin(YearOffset): + """ + DateOffset increments between calendar year begin dates. + + Examples + -------- + >>> from pandas.tseries.offsets import YearBegin + >>> ts = pd.Timestamp('2020-05-24 05:01:15') + >>> ts + YearBegin() + Timestamp('2021-01-01 05:01:15') + >>> ts + YearBegin(normalize = True) + Timestamp('2021-01-01 00:00:00') + >>> ts + YearBegin()._from_name('APR') + Timestamp('2021-04-01 05:01:15') """ - DateOffset increments between the last business day of the year. + _outputName = "YearBegin" + _default_month = 1 + _prefix = "AS" + _day_opt = "start" + + +cdef class YearEnd(YearOffset): + """ + DateOffset increments between calendar year ends. + Examples -------- - >>> from pandas.tseries.offset import BYearEnd + >>> from pandas.tseries.offsets import YearEnd >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts - BYearEnd() - Timestamp('2019-12-31 05:01:15') - >>> ts + BYearEnd() + >>> ts + YearEnd() Timestamp('2020-12-31 05:01:15') - >>> ts + BYearEnd(3) - Timestamp('2022-12-30 05:01:15') - >>> ts + BYearEnd(-3) - Timestamp('2017-12-29 05:01:15') - >>> ts + BYearEnd(month=11) - Timestamp('2020-11-30 05:01:15') + >>> ts + YearEnd(normalize = True) + Timestamp('2020-12-31 00:00:00') + >>> ts + YearEnd()._from_name('AUG') + Timestamp('2020-08-31 05:01:15') """ - _outputName = "BusinessYearEnd" + _outputName = "YearEnd" _default_month = 12 - _prefix = "BA" - _day_opt = "business_end" - - + _prefix = "A" + _day_opt = "end" + + cdef class BYearBegin(YearOffset): """ DateOffset increments between the first business day of the year. Examples -------- - >>> from pandas.tseries.offset import BYearBegin + >>> from pandas.tseries.offsets import BYearBegin >>> ts = pd.Timestamp('2020-05-24 05:01:15') >>> ts + BYearBegin() Timestamp('2021-01-01 05:01:15') @@ -1951,36 +1973,47 @@ cdef class BYearBegin(YearOffset): _default_month = 1 _prefix = "BAS" _day_opt = "business_start" + - -cdef class YearEnd(YearOffset): - """ - DateOffset increments between calendar year ends. +cdef class BYearEnd(YearOffset): """ + DateOffset increments between the last business days of offset years. + Here, the year is a period of 12 consecutive calendar months + (January - December by default). The "month" parameter allows custom setting + of the final month in a year (and correspondingly - the year start month). + + Parameters + ---------- + n : int, default 1 + Number of years to offset. + normalize: bool, default False + If true, the time component of the resulting date-time is converted to + 00:00:00, i.e. midnight (the start, not the end of date-time). + month: int, default 12 + The calendar month number (12 for December) of the ending month + in a custom-defined year to be used as offset. - _default_month = 12 - _prefix = "A" - _day_opt = "end" - - cdef readonly: - int _period_dtype_code - - def __init__(self, n=1, normalize=False, month=None): - # Because YearEnd can be the freq for a Period, define its - # _period_dtype_code at construction for performance - YearOffset.__init__(self, n, normalize, month) - self._period_dtype_code = PeriodDtypeCode.A + self.month % 12 - - -cdef class YearBegin(YearOffset): - """ - DateOffset increments between calendar year begin dates. + Examples + -------- + >>> from pandas.tseries.offsets import BYearEnd + >>> ts = pd.Timestamp('2020-05-24 05:01:15') + >>> ts - BYearEnd() + Timestamp('2019-12-31 05:01:15') + >>> ts + BYearEnd() + Timestamp('2020-12-31 05:01:15') + >>> ts + BYearEnd(3) + Timestamp('2022-12-30 05:01:15') + >>> ts + BYearEnd(-3) + Timestamp('2017-12-29 05:01:15') + >>> ts + BYearEnd(month=11) + Timestamp('2020-11-30 05:01:15') """ - _default_month = 1 - _prefix = "AS" - _day_opt = "start" - + _outputName = "BusinessYearEnd" + _default_month = 12 + _prefix = "BA" + _day_opt = "business_end" + # ---------------------------------------------------------------------- # Quarter-Based Offset Classes @@ -1991,19 +2024,21 @@ cdef class QuarterOffset(SingleConstructorOffset): # point. Also apply_index, is_on_offset, rule_code if # startingMonth vs month attr names are resolved - # FIXME: python annotations here breaks things - # _default_starting_month: int - # _from_name_starting_month: int cdef readonly: - int startingMonth + int startingMonth, _default_month, _period_dtype_code def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) - - if startingMonth is None: - startingMonth = self._default_starting_month - self.startingMonth = startingMonth + + if startingMonth is not None: + if startingMonth < 1 or startingMonth > 12: + raise ValueError("Month must go from 1 to 12") + self.startingMonth = startingMonth + else: + self.startingMonth = self._default_month + + self._period_dtype_code = PeriodDtypeCode.Q_DEC + self.startingMonth % 12 cpdef __setstate__(self, state): self.startingMonth = state.pop("startingMonth") @@ -2016,8 +2051,8 @@ cdef class QuarterOffset(SingleConstructorOffset): if suffix: kwargs["startingMonth"] = MONTH_TO_CAL_NUM[suffix] else: - if cls._from_name_starting_month is not None: - kwargs["startingMonth"] = cls._from_name_starting_month + if cls._default_month is not None: + kwargs["startingMonth"] = cls._default_month return cls(**kwargs) @property @@ -2070,7 +2105,7 @@ cdef class BQuarterEnd(QuarterOffset): Examples -------- - >>> from pandas.tseries.offset import BQuarterEnd + >>> from pandas.tseries.offsets import BQuarterEnd >>> ts = pd.Timestamp('2020-05-24 05:01:15') >>> ts + BQuarterEnd() Timestamp('2020-06-30 05:01:15') @@ -2081,9 +2116,9 @@ cdef class BQuarterEnd(QuarterOffset): >>> ts + BQuarterEnd(startingMonth=2) Timestamp('2020-05-29 05:01:15') """ + _output_name = "BusinessQuarterEnd" - _default_starting_month = 3 - _from_name_starting_month = 12 + _default_month = 3 _prefix = "BQ" _day_opt = "business_end" @@ -2098,20 +2133,20 @@ cdef class BQuarterBegin(QuarterOffset): Examples -------- - >>> from pandas.tseries.offset import BQuarterBegin + >>> from pandas.tseries.offsets import BQuarterBegin >>> ts = pd.Timestamp('2020-05-24 05:01:15') >>> ts + BQuarterBegin() - Timestamp('2020-06-01 05:01:15') + Timestamp('2020-07-01 05:01:15') >>> ts + BQuarterBegin(2) - Timestamp('2020-09-01 05:01:15') + Timestamp('2020-10-01 05:01:15') >>> ts + BQuarterBegin(startingMonth=2) Timestamp('2020-08-03 05:01:15') >>> ts + BQuarterBegin(-1) - Timestamp('2020-03-02 05:01:15') + Timestamp('2020-04-01 05:01:15') """ + _output_name = "BusinessQuarterBegin" - _default_starting_month = 3 - _from_name_starting_month = 1 + _default_month = 1 _prefix = "BQS" _day_opt = "business_start" @@ -2123,20 +2158,26 @@ cdef class QuarterEnd(QuarterOffset): startingMonth = 1 corresponds to dates like 1/31/2007, 4/30/2007, ... startingMonth = 2 corresponds to dates like 2/28/2007, 5/31/2007, ... startingMonth = 3 corresponds to dates like 3/31/2007, 6/30/2007, ... + + Examples + -------- + >>> from pandas.tseries.offsets import QuarterEnd + >>> ts = pd.Timestamp('2020-05-24 05:01:15') + >>> ts + QuarterEnd(2) + Timestamp('2020-09-30 05:01:15') + >>> ts + QuarterEnd()._from_name('JUN') + Timestamp('2020-06-30 05:01:15') + >>> ts + QuarterEnd(1, normalize = True) + Timestamp('2020-06-30 00:00:00') + >>> ts + QuarterEnd(-2, startingMonth = 2) + Timestamp('2019-11-30 05:01:15') """ - _default_starting_month = 3 + + _output_name = "QuarterEnd" + _default_month = 3 _prefix = "Q" _day_opt = "end" - cdef readonly: - int _period_dtype_code - - def __init__(self, n=1, normalize=False, startingMonth=None): - # Because QuarterEnd can be the freq for a Period, define its - # _period_dtype_code at construction for performance - QuarterOffset.__init__(self, n, normalize, startingMonth) - self._period_dtype_code = PeriodDtypeCode.Q_DEC + self.startingMonth % 12 - cdef class QuarterBegin(QuarterOffset): """ @@ -2145,9 +2186,23 @@ cdef class QuarterBegin(QuarterOffset): startingMonth = 1 corresponds to dates like 1/01/2007, 4/01/2007, ... startingMonth = 2 corresponds to dates like 2/01/2007, 5/01/2007, ... startingMonth = 3 corresponds to dates like 3/01/2007, 6/01/2007, ... + + Examples + -------- + >>> from pandas.tseries.offsets import QuarterBegin + >>> ts = pd.Timestamp('2020-05-24 05:01:15') + >>> ts + QuarterBegin()._from_name('MAR') + Timestamp('2020-06-01 05:01:15') + >>> ts + QuarterBegin() + Timestamp('2020-07-01 05:01:15') + >>> ts + QuarterBegin(2) + Timestamp('2020-10-01 05:01:15') + >>> ts + QuarterBegin(2, startingMonth = 2) + Timestamp('2020-11-01 05:01:15') """ - _default_starting_month = 3 - _from_name_starting_month = 1 + + _output_name = "QuarterBegin" + _default_month = 1 _prefix = "QS" _day_opt = "start" @@ -2156,6 +2211,11 @@ cdef class QuarterBegin(QuarterOffset): # Month-Based Offset Classes cdef class MonthOffset(SingleConstructorOffset): + cdef readonly: + int _period_dtype_code + + _period_dtype_code = PeriodDtypeCode.M + def is_on_offset(self, dt: datetime) -> bool: if self.normalize and not _is_normalized(dt): return False @@ -2184,22 +2244,43 @@ cdef class MonthOffset(SingleConstructorOffset): BaseOffset.__setstate__(self, state) + +cdef class MonthBegin(MonthOffset): + """ + DateOffset of one month at beginning. + """ + _prefix = "MS" + _day_opt = "start" + + cdef class MonthEnd(MonthOffset): """ DateOffset of one month end. """ - _period_dtype_code = PeriodDtypeCode.M + _prefix = "M" _day_opt = "end" -cdef class MonthBegin(MonthOffset): +cdef class BusinessMonthBegin(MonthOffset): """ - DateOffset of one month at beginning. + DateOffset of one month at the first business day. + + Examples + -------- + >>> from pandas.tseries.offset import BMonthBegin + >>> ts=pd.Timestamp('2020-05-24 05:01:15') + >>> ts + BMonthBegin() + Timestamp('2020-06-01 05:01:15') + >>> ts + BMonthBegin(2) + Timestamp('2020-07-01 05:01:15') + >>> ts + BMonthBegin(-3) + Timestamp('2020-03-02 05:01:15') """ - _prefix = "MS" - _day_opt = "start" + + _prefix = "BMS" + _day_opt = "business_start" cdef class BusinessMonthEnd(MonthOffset): @@ -2217,29 +2298,11 @@ cdef class BusinessMonthEnd(MonthOffset): >>> ts + BMonthEnd(-2) Timestamp('2020-03-31 05:01:15') """ + _prefix = "BM" _day_opt = "business_end" -cdef class BusinessMonthBegin(MonthOffset): - """ - DateOffset of one month at the first business day. - - Examples - -------- - >>> from pandas.tseries.offset import BMonthBegin - >>> ts=pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BMonthBegin() - Timestamp('2020-06-01 05:01:15') - >>> ts + BMonthBegin(2) - Timestamp('2020-07-01 05:01:15') - >>> ts + BMonthBegin(-3) - Timestamp('2020-03-02 05:01:15') - """ - _prefix = "BMS" - _day_opt = "business_start" - - # --------------------------------------------------------------------- # Semi-Month Based Offsets From 87e1b87610ccd1e0e430d739d6eebc50aa1481bd Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Wed, 17 Feb 2021 23:32:00 +0100 Subject: [PATCH 02/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 14dac644442a1..5c73c373e73ff 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1840,9 +1840,11 @@ cdef class YearOffset(SingleConstructorOffset): """ _attributes = tuple(["n", "normalize", "month"]) + _default_month = 1 + _period_dtype_code = None cdef readonly: - int month, _default_month, _period_dtype_code + int month def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) @@ -2019,14 +2021,19 @@ cdef class BYearEnd(YearOffset): # Quarter-Based Offset Classes cdef class QuarterOffset(SingleConstructorOffset): - _attributes = tuple(["n", "normalize", "startingMonth"]) + """ + The baseline quarterly DateOffset that just needs a month. + """ # TODO: Consider combining QuarterOffset and YearOffset __init__ at some # point. Also apply_index, is_on_offset, rule_code if # startingMonth vs month attr names are resolved - + + _attributes = tuple(["n", "normalize", "startingMonth"]) + _default_month = 1 + _period_dtype_code = None cdef readonly: - int startingMonth, _default_month, _period_dtype_code + int startingMonth def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) @@ -2211,9 +2218,6 @@ cdef class QuarterBegin(QuarterOffset): # Month-Based Offset Classes cdef class MonthOffset(SingleConstructorOffset): - cdef readonly: - int _period_dtype_code - _period_dtype_code = PeriodDtypeCode.M def is_on_offset(self, dt: datetime) -> bool: From 5d46697334e3264b72d9b5205d782c44b576e5f9 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 00:07:46 +0100 Subject: [PATCH 03/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 126 ++++++++++++++++---------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 5c73c373e73ff..de5579e9bdfd7 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1840,8 +1840,8 @@ cdef class YearOffset(SingleConstructorOffset): """ _attributes = tuple(["n", "normalize", "month"]) - _default_month = 1 - _period_dtype_code = None + cdef _default_month int = 1 + cdef _period_dtype_code int = None cdef readonly: int month @@ -1853,7 +1853,7 @@ cdef class YearOffset(SingleConstructorOffset): self.month = month if month < 1 or month > 12: - raise ValueError("Month must go from 1 to 12") + raise ValueError("Month must go from 1 to 12.") self._period_dtype_code = PeriodDtypeCode.A + self.month % 12 @@ -2029,8 +2029,8 @@ cdef class QuarterOffset(SingleConstructorOffset): # startingMonth vs month attr names are resolved _attributes = tuple(["n", "normalize", "startingMonth"]) - _default_month = 1 - _period_dtype_code = None + cdef _default_month int = 1 + cdef _period_dtype_code int = None cdef readonly: int startingMonth @@ -2040,7 +2040,7 @@ cdef class QuarterOffset(SingleConstructorOffset): if startingMonth is not None: if startingMonth < 1 or startingMonth > 12: - raise ValueError("Month must go from 1 to 12") + raise ValueError("Month must go from 1 to 12.") self.startingMonth = startingMonth else: self.startingMonth = self._default_month @@ -2101,62 +2101,34 @@ cdef class QuarterOffset(SingleConstructorOffset): ) return shifted - -cdef class BQuarterEnd(QuarterOffset): - """ - DateOffset increments between the last business day of each Quarter. - - startingMonth = 1 corresponds to dates like 1/31/2007, 4/30/2007, ... - startingMonth = 2 corresponds to dates like 2/28/2007, 5/31/2007, ... - startingMonth = 3 corresponds to dates like 3/30/2007, 6/29/2007, ... - - Examples - -------- - >>> from pandas.tseries.offsets import BQuarterEnd - >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BQuarterEnd() - Timestamp('2020-06-30 05:01:15') - >>> ts + BQuarterEnd(2) - Timestamp('2020-09-30 05:01:15') - >>> ts + BQuarterEnd(1, startingMonth=2) - Timestamp('2020-05-29 05:01:15') - >>> ts + BQuarterEnd(startingMonth=2) - Timestamp('2020-05-29 05:01:15') - """ - _output_name = "BusinessQuarterEnd" - _default_month = 3 - _prefix = "BQ" - _day_opt = "business_end" - - -cdef class BQuarterBegin(QuarterOffset): +cdef class QuarterBegin(QuarterOffset): """ - DateOffset increments between the first business day of each Quarter. + DateOffset increments between Quarter start dates. startingMonth = 1 corresponds to dates like 1/01/2007, 4/01/2007, ... startingMonth = 2 corresponds to dates like 2/01/2007, 5/01/2007, ... startingMonth = 3 corresponds to dates like 3/01/2007, 6/01/2007, ... - + Examples -------- - >>> from pandas.tseries.offsets import BQuarterBegin + >>> from pandas.tseries.offsets import QuarterBegin >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BQuarterBegin() + >>> ts + QuarterBegin()._from_name('MAR') + Timestamp('2020-06-01 05:01:15') + >>> ts + QuarterBegin() Timestamp('2020-07-01 05:01:15') - >>> ts + BQuarterBegin(2) + >>> ts + QuarterBegin(2) Timestamp('2020-10-01 05:01:15') - >>> ts + BQuarterBegin(startingMonth=2) - Timestamp('2020-08-03 05:01:15') - >>> ts + BQuarterBegin(-1) - Timestamp('2020-04-01 05:01:15') + >>> ts + QuarterBegin(2, startingMonth = 2) + Timestamp('2020-11-01 05:01:15') """ - _output_name = "BusinessQuarterBegin" + _output_name = "QuarterBegin" _default_month = 1 - _prefix = "BQS" - _day_opt = "business_start" - + _prefix = "QS" + _day_opt = "start" + cdef class QuarterEnd(QuarterOffset): """ @@ -2184,34 +2156,62 @@ cdef class QuarterEnd(QuarterOffset): _default_month = 3 _prefix = "Q" _day_opt = "end" + - -cdef class QuarterBegin(QuarterOffset): +cdef class BQuarterBegin(QuarterOffset): """ - DateOffset increments between Quarter start dates. + DateOffset increments between the first business day of each Quarter. startingMonth = 1 corresponds to dates like 1/01/2007, 4/01/2007, ... startingMonth = 2 corresponds to dates like 2/01/2007, 5/01/2007, ... startingMonth = 3 corresponds to dates like 3/01/2007, 6/01/2007, ... - + Examples -------- - >>> from pandas.tseries.offsets import QuarterBegin + >>> from pandas.tseries.offsets import BQuarterBegin >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + QuarterBegin()._from_name('MAR') - Timestamp('2020-06-01 05:01:15') - >>> ts + QuarterBegin() + >>> ts + BQuarterBegin() Timestamp('2020-07-01 05:01:15') - >>> ts + QuarterBegin(2) + >>> ts + BQuarterBegin(2) Timestamp('2020-10-01 05:01:15') - >>> ts + QuarterBegin(2, startingMonth = 2) - Timestamp('2020-11-01 05:01:15') + >>> ts + BQuarterBegin(startingMonth=2) + Timestamp('2020-08-03 05:01:15') + >>> ts + BQuarterBegin(-1) + Timestamp('2020-04-01 05:01:15') """ - _output_name = "QuarterBegin" + _output_name = "BusinessQuarterBegin" _default_month = 1 - _prefix = "QS" - _day_opt = "start" + _prefix = "BQS" + _day_opt = "business_start" + + +cdef class BQuarterEnd(QuarterOffset): + """ + DateOffset increments between the last business day of each Quarter. + + startingMonth = 1 corresponds to dates like 1/31/2007, 4/30/2007, ... + startingMonth = 2 corresponds to dates like 2/28/2007, 5/31/2007, ... + startingMonth = 3 corresponds to dates like 3/30/2007, 6/29/2007, ... + + Examples + -------- + >>> from pandas.tseries.offsets import BQuarterEnd + >>> ts = pd.Timestamp('2020-05-24 05:01:15') + >>> ts + BQuarterEnd() + Timestamp('2020-06-30 05:01:15') + >>> ts + BQuarterEnd(2) + Timestamp('2020-09-30 05:01:15') + >>> ts + BQuarterEnd(1, startingMonth=2) + Timestamp('2020-05-29 05:01:15') + >>> ts + BQuarterEnd(startingMonth=2) + Timestamp('2020-05-29 05:01:15') + """ + + _output_name = "BusinessQuarterEnd" + _default_month = 3 + _prefix = "BQ" + _day_opt = "business_end" # ---------------------------------------------------------------------- @@ -2328,7 +2328,7 @@ cdef class SemiMonthOffset(SingleConstructorOffset): if not self._min_day_of_month <= self.day_of_month <= 27: raise ValueError( "day_of_month must be " - f"{self._min_day_of_month}<=day_of_month<=27, " + f"{self._min_day_of_month} <= day_of_month <= 27, " f"got {self.day_of_month}" ) From a58390560b98fe4c78ea62f514ff5d8dcb754069 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 00:11:24 +0100 Subject: [PATCH 04/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index de5579e9bdfd7..fb30e4067c3ea 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1840,8 +1840,7 @@ cdef class YearOffset(SingleConstructorOffset): """ _attributes = tuple(["n", "normalize", "month"]) - cdef _default_month int = 1 - cdef _period_dtype_code int = None + cdef int _default_month, _period_dtype_code cdef readonly: int month @@ -2029,8 +2028,7 @@ cdef class QuarterOffset(SingleConstructorOffset): # startingMonth vs month attr names are resolved _attributes = tuple(["n", "normalize", "startingMonth"]) - cdef _default_month int = 1 - cdef _period_dtype_code int = None + cdef int _default_month, _period_dtype_code cdef readonly: int startingMonth From cd216aeb79139fb51bcd7fee4fd8a030cf9ea2ab Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 00:13:43 +0100 Subject: [PATCH 05/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index fb30e4067c3ea..6312f4b6a3a1d 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1840,7 +1840,8 @@ cdef class YearOffset(SingleConstructorOffset): """ _attributes = tuple(["n", "normalize", "month"]) - cdef int _default_month, _period_dtype_code + _default_month = 1 + cdef int _period_dtype_code cdef readonly: int month @@ -2028,7 +2029,8 @@ cdef class QuarterOffset(SingleConstructorOffset): # startingMonth vs month attr names are resolved _attributes = tuple(["n", "normalize", "startingMonth"]) - cdef int _default_month, _period_dtype_code + _default_month = 1 + cdef int _period_dtype_code cdef readonly: int startingMonth From 53b09c19e9b77edc0c4bb98b51b356c966e15443 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 01:10:29 +0100 Subject: [PATCH 06/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 6312f4b6a3a1d..8b03a9e0f641e 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1841,10 +1841,9 @@ cdef class YearOffset(SingleConstructorOffset): _attributes = tuple(["n", "normalize", "month"]) _default_month = 1 - cdef int _period_dtype_code + cdef public int _period_dtype_code - cdef readonly: - int month + cdef readonly int month def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) @@ -2030,10 +2029,9 @@ cdef class QuarterOffset(SingleConstructorOffset): _attributes = tuple(["n", "normalize", "startingMonth"]) _default_month = 1 - cdef int _period_dtype_code + cdef public int _period_dtype_code - cdef readonly: - int startingMonth + cdef readonly int startingMonth def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) From 6fdb0afa61882b88cd49b44d09c979b5f2774608 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 07:51:33 +0100 Subject: [PATCH 07/64] Update offsets.pyx Minor formatting changes. --- pandas/_libs/tslibs/offsets.pyx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 8b03a9e0f641e..cbed3584a1eff 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1841,9 +1841,11 @@ cdef class YearOffset(SingleConstructorOffset): _attributes = tuple(["n", "normalize", "month"]) _default_month = 1 - cdef public int _period_dtype_code + cdef public: + int _period_dtype_code - cdef readonly int month + cdef readonly: + int month def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) @@ -2029,9 +2031,11 @@ cdef class QuarterOffset(SingleConstructorOffset): _attributes = tuple(["n", "normalize", "startingMonth"]) _default_month = 1 - cdef public int _period_dtype_code + cdef public: + int _period_dtype_code - cdef readonly int startingMonth + cdef readonly: + int startingMonth def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) From b7d671b3179332d6fb96620c9893e43aaa7574ba Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 08:36:00 +0100 Subject: [PATCH 08/64] Update offsets.pyx Minor formatting changes. --- pandas/_libs/tslibs/offsets.pyx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index cbed3584a1eff..6d3eebf967ce4 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1841,11 +1841,10 @@ cdef class YearOffset(SingleConstructorOffset): _attributes = tuple(["n", "normalize", "month"]) _default_month = 1 - cdef public: - int _period_dtype_code - - cdef readonly: - int month + + cdef: + public int _period_dtype_code + readonly int month def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) @@ -2031,11 +2030,10 @@ cdef class QuarterOffset(SingleConstructorOffset): _attributes = tuple(["n", "normalize", "startingMonth"]) _default_month = 1 - cdef public: - int _period_dtype_code - - cdef readonly: - int startingMonth + + cdef: + public int _period_dtype_code + readonly int startingMonth def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) From de720738a34b251aebd7cebe87ffc82f07854371 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 10:03:19 +0100 Subject: [PATCH 09/64] Add ability to provide months as short names --- pandas/_libs/tslibs/offsets.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 6d3eebf967ce4..580cf1eb81ef0 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2039,6 +2039,8 @@ cdef class QuarterOffset(SingleConstructorOffset): BaseOffset.__init__(self, n, normalize) if startingMonth is not None: + if isinstance(startingMonth, str): + startingMonth = MONTH_TO_CAL_NUM[suffix] if startingMonth < 1 or startingMonth > 12: raise ValueError("Month must go from 1 to 12.") self.startingMonth = startingMonth From bfaf6ce75a65eb45ff8c9dcec6c99034622f7d80 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 10:05:20 +0100 Subject: [PATCH 10/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 580cf1eb81ef0..189b22e96152c 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2040,7 +2040,7 @@ cdef class QuarterOffset(SingleConstructorOffset): if startingMonth is not None: if isinstance(startingMonth, str): - startingMonth = MONTH_TO_CAL_NUM[suffix] + startingMonth = MONTH_TO_CAL_NUM[startingMonth] if startingMonth < 1 or startingMonth > 12: raise ValueError("Month must go from 1 to 12.") self.startingMonth = startingMonth From 1b396dde78110eab1eb6e468bea8b3f0faacee29 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 10:16:35 +0100 Subject: [PATCH 11/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 189b22e96152c..321c870cf9283 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1849,11 +1849,14 @@ cdef class YearOffset(SingleConstructorOffset): def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) - month = month if month is not None else self._default_month - self.month = month - - if month < 1 or month > 12: - raise ValueError("Month must go from 1 to 12.") + if month is not None: + if isinstance(month, str): + month = MONTH_TO_CAL_NUM[month] + if month < 1 or month > 12: + raise ValueError("Month must go from 1 to 12.") + self.month = month + else: + self.month = self._default_month self._period_dtype_code = PeriodDtypeCode.A + self.month % 12 From d7f702024b1669433e59fe05bd2bc40c5c8706bd Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 10:45:06 +0100 Subject: [PATCH 12/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 321c870cf9283..cae19a6f49202 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1851,10 +1851,11 @@ cdef class YearOffset(SingleConstructorOffset): if month is not None: if isinstance(month, str): - month = MONTH_TO_CAL_NUM[month] - if month < 1 or month > 12: + self.month = MONTH_TO_CAL_NUM[month] + elif month >= 1 and month <= 12: + self.month = month + else: raise ValueError("Month must go from 1 to 12.") - self.month = month else: self.month = self._default_month @@ -2043,10 +2044,11 @@ cdef class QuarterOffset(SingleConstructorOffset): if startingMonth is not None: if isinstance(startingMonth, str): - startingMonth = MONTH_TO_CAL_NUM[startingMonth] - if startingMonth < 1 or startingMonth > 12: + self.startingMonth = MONTH_TO_CAL_NUM[startingMonth] + elif startingMonth >= 1 and startingMonth <= 12: + self.startingMonth = startingMonth + else: raise ValueError("Month must go from 1 to 12.") - self.startingMonth = startingMonth else: self.startingMonth = self._default_month From ca67f8ad8a0840a9d4cb42d0c70e4cb1521f107a Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 10:55:06 +0100 Subject: [PATCH 13/64] Update offsets.pyx Temporary unfixing of the default months for `QuarterBegin` and `BQuarterBegin`. --- pandas/_libs/tslibs/offsets.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index cae19a6f49202..ebebf221e2641 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2132,7 +2132,7 @@ cdef class QuarterBegin(QuarterOffset): """ _output_name = "QuarterBegin" - _default_month = 1 + _default_month = 3 # 1 _prefix = "QS" _day_opt = "start" @@ -2188,7 +2188,7 @@ cdef class BQuarterBegin(QuarterOffset): """ _output_name = "BusinessQuarterBegin" - _default_month = 1 + _default_month = 3 # 1 _prefix = "BQS" _day_opt = "business_start" From e04e27d8a1f1e64603bd0d19566e8ae444554859 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 11:58:58 +0100 Subject: [PATCH 14/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 82 ++++++++++++++++----------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index ebebf221e2641..1c2c8e4d367c4 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1838,10 +1838,10 @@ cdef class YearOffset(SingleConstructorOffset): """ DateOffset that just needs a month. """ - + _attributes = tuple(["n", "normalize", "month"]) _default_month = 1 - + cdef: public int _period_dtype_code readonly int month @@ -1855,10 +1855,10 @@ cdef class YearOffset(SingleConstructorOffset): elif month >= 1 and month <= 12: self.month = month else: - raise ValueError("Month must go from 1 to 12.") + raise ValueError("Month must go from 1 to 12.") else: self.month = self._default_month - + self._period_dtype_code = PeriodDtypeCode.A + self.month % 12 cpdef __setstate__(self, state): @@ -1876,7 +1876,7 @@ cdef class YearOffset(SingleConstructorOffset): if cls._default_month is not None: kwargs["month"] = cls._default_month return cls(**kwargs) - + @property def rule_code(self) -> str: month = MONTH_ALIASES[self.month] @@ -1912,11 +1912,11 @@ cdef class YearOffset(SingleConstructorOffset): ) return shifted - + cdef class YearBegin(YearOffset): """ DateOffset increments between calendar year begin dates. - + Examples -------- >>> from pandas.tseries.offsets import YearBegin @@ -1933,12 +1933,12 @@ cdef class YearBegin(YearOffset): _default_month = 1 _prefix = "AS" _day_opt = "start" - + cdef class YearEnd(YearOffset): """ DateOffset increments between calendar year ends. - + Examples -------- >>> from pandas.tseries.offsets import YearEnd @@ -1955,8 +1955,8 @@ cdef class YearEnd(YearOffset): _default_month = 12 _prefix = "A" _day_opt = "end" - - + + cdef class BYearBegin(YearOffset): """ DateOffset increments between the first business day of the year. @@ -1979,24 +1979,24 @@ cdef class BYearBegin(YearOffset): _default_month = 1 _prefix = "BAS" _day_opt = "business_start" - + cdef class BYearEnd(YearOffset): """ DateOffset increments between the last business days of offset years. Here, the year is a period of 12 consecutive calendar months - (January - December by default). The "month" parameter allows custom setting - of the final month in a year (and correspondingly - the year start month). - + (January - December by default). The "month" parameter allows custom setting + of the final month in a year (and correspondingly - the year start month). + Parameters ---------- n : int, default 1 Number of years to offset. normalize: bool, default False - If true, the time component of the resulting date-time is converted to + If true, the time component of the resulting date-time is converted to 00:00:00, i.e. midnight (the start, not the end of date-time). month: int, default 12 - The calendar month number (12 for December) of the ending month + The calendar month number (12 for December) of the ending month in a custom-defined year to be used as offset. Examples @@ -2019,7 +2019,7 @@ cdef class BYearEnd(YearOffset): _default_month = 12 _prefix = "BA" _day_opt = "business_end" - + # ---------------------------------------------------------------------- # Quarter-Based Offset Classes @@ -2031,27 +2031,27 @@ cdef class QuarterOffset(SingleConstructorOffset): # TODO: Consider combining QuarterOffset and YearOffset __init__ at some # point. Also apply_index, is_on_offset, rule_code if # startingMonth vs month attr names are resolved - + _attributes = tuple(["n", "normalize", "startingMonth"]) _default_month = 1 - + cdef: public int _period_dtype_code readonly int startingMonth def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) - + if startingMonth is not None: if isinstance(startingMonth, str): self.startingMonth = MONTH_TO_CAL_NUM[startingMonth] elif startingMonth >= 1 and startingMonth <= 12: self.startingMonth = startingMonth else: - raise ValueError("Month must go from 1 to 12.") + raise ValueError("Month must go from 1 to 12.") else: self.startingMonth = self._default_month - + self._period_dtype_code = PeriodDtypeCode.Q_DEC + self.startingMonth % 12 cpdef __setstate__(self, state): @@ -2108,7 +2108,7 @@ cdef class QuarterOffset(SingleConstructorOffset): ) return shifted - + cdef class QuarterBegin(QuarterOffset): """ DateOffset increments between Quarter start dates. @@ -2116,7 +2116,7 @@ cdef class QuarterBegin(QuarterOffset): startingMonth = 1 corresponds to dates like 1/01/2007, 4/01/2007, ... startingMonth = 2 corresponds to dates like 2/01/2007, 5/01/2007, ... startingMonth = 3 corresponds to dates like 3/01/2007, 6/01/2007, ... - + Examples -------- >>> from pandas.tseries.offsets import QuarterBegin @@ -2130,12 +2130,12 @@ cdef class QuarterBegin(QuarterOffset): >>> ts + QuarterBegin(2, startingMonth = 2) Timestamp('2020-11-01 05:01:15') """ - + _output_name = "QuarterBegin" - _default_month = 3 # 1 + _default_month = 1 _prefix = "QS" _day_opt = "start" - + cdef class QuarterEnd(QuarterOffset): """ @@ -2144,7 +2144,7 @@ cdef class QuarterEnd(QuarterOffset): startingMonth = 1 corresponds to dates like 1/31/2007, 4/30/2007, ... startingMonth = 2 corresponds to dates like 2/28/2007, 5/31/2007, ... startingMonth = 3 corresponds to dates like 3/31/2007, 6/30/2007, ... - + Examples -------- >>> from pandas.tseries.offsets import QuarterEnd @@ -2158,12 +2158,12 @@ cdef class QuarterEnd(QuarterOffset): >>> ts + QuarterEnd(-2, startingMonth = 2) Timestamp('2019-11-30 05:01:15') """ - + _output_name = "QuarterEnd" _default_month = 3 _prefix = "Q" _day_opt = "end" - + cdef class BQuarterBegin(QuarterOffset): """ @@ -2186,13 +2186,13 @@ cdef class BQuarterBegin(QuarterOffset): >>> ts + BQuarterBegin(-1) Timestamp('2020-04-01 05:01:15') """ - + _output_name = "BusinessQuarterBegin" - _default_month = 3 # 1 + _default_month = 1 _prefix = "BQS" _day_opt = "business_start" - + cdef class BQuarterEnd(QuarterOffset): """ DateOffset increments between the last business day of each Quarter. @@ -2214,7 +2214,7 @@ cdef class BQuarterEnd(QuarterOffset): >>> ts + BQuarterEnd(startingMonth=2) Timestamp('2020-05-29 05:01:15') """ - + _output_name = "BusinessQuarterEnd" _default_month = 3 _prefix = "BQ" @@ -2226,7 +2226,7 @@ cdef class BQuarterEnd(QuarterOffset): cdef class MonthOffset(SingleConstructorOffset): _period_dtype_code = PeriodDtypeCode.M - + def is_on_offset(self, dt: datetime) -> bool: if self.normalize and not _is_normalized(dt): return False @@ -2255,7 +2255,7 @@ cdef class MonthOffset(SingleConstructorOffset): BaseOffset.__setstate__(self, state) - + cdef class MonthBegin(MonthOffset): """ DateOffset of one month at beginning. @@ -2263,8 +2263,8 @@ cdef class MonthBegin(MonthOffset): _prefix = "MS" _day_opt = "start" - - + + cdef class MonthEnd(MonthOffset): """ DateOffset of one month end. @@ -2289,7 +2289,7 @@ cdef class BusinessMonthBegin(MonthOffset): >>> ts + BMonthBegin(-3) Timestamp('2020-03-02 05:01:15') """ - + _prefix = "BMS" _day_opt = "business_start" @@ -2309,7 +2309,7 @@ cdef class BusinessMonthEnd(MonthOffset): >>> ts + BMonthEnd(-2) Timestamp('2020-03-31 05:01:15') """ - + _prefix = "BM" _day_opt = "business_end" From d4d87c4725fec0ce82fc1f449221015d5dc8a498 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 12:12:38 +0100 Subject: [PATCH 15/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 1c2c8e4d367c4..2102fa891f5cb 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2132,7 +2132,7 @@ cdef class QuarterBegin(QuarterOffset): """ _output_name = "QuarterBegin" - _default_month = 1 + _default_month = 3 #1 _prefix = "QS" _day_opt = "start" @@ -2188,7 +2188,7 @@ cdef class BQuarterBegin(QuarterOffset): """ _output_name = "BusinessQuarterBegin" - _default_month = 1 + _default_month = 3 #1 _prefix = "BQS" _day_opt = "business_start" @@ -2261,6 +2261,7 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ + _period_dtype_code = None _prefix = "MS" _day_opt = "start" From 2c22a3171239006b9a62fd8643abef8f4300c6b4 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 12:26:16 +0100 Subject: [PATCH 16/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 2102fa891f5cb..a02d1df9be3cf 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2132,7 +2132,7 @@ cdef class QuarterBegin(QuarterOffset): """ _output_name = "QuarterBegin" - _default_month = 3 #1 + _default_month = 3 # should be 1 _prefix = "QS" _day_opt = "start" @@ -2188,7 +2188,7 @@ cdef class BQuarterBegin(QuarterOffset): """ _output_name = "BusinessQuarterBegin" - _default_month = 3 #1 + _default_month = 3 # Should be 1 _prefix = "BQS" _day_opt = "business_start" From 11cb0b51403834394de6850710193c20fd054fe5 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 13:29:33 +0100 Subject: [PATCH 17/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index a02d1df9be3cf..281ff1ed010ec 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1992,10 +1992,10 @@ cdef class BYearEnd(YearOffset): ---------- n : int, default 1 Number of years to offset. - normalize: bool, default False + normalize : bool, default False If true, the time component of the resulting date-time is converted to 00:00:00, i.e. midnight (the start, not the end of date-time). - month: int, default 12 + month : int, default 12 The calendar month number (12 for December) of the ending month in a custom-defined year to be used as offset. @@ -2261,7 +2261,7 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ - _period_dtype_code = None + del(_period_dtype_code) _prefix = "MS" _day_opt = "start" From 71e9cab775502f31c2450a42521aa388d84e7c18 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 13:40:13 +0100 Subject: [PATCH 18/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 281ff1ed010ec..9858009c99711 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2225,7 +2225,7 @@ cdef class BQuarterEnd(QuarterOffset): # Month-Based Offset Classes cdef class MonthOffset(SingleConstructorOffset): - _period_dtype_code = PeriodDtypeCode.M + # _period_dtype_code = PeriodDtypeCode.M def is_on_offset(self, dt: datetime) -> bool: if self.normalize and not _is_normalized(dt): @@ -2261,7 +2261,6 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ - del(_period_dtype_code) _prefix = "MS" _day_opt = "start" @@ -2271,6 +2270,7 @@ cdef class MonthEnd(MonthOffset): DateOffset of one month end. """ + _period_dtype_code = M _prefix = "M" _day_opt = "end" @@ -2311,6 +2311,7 @@ cdef class BusinessMonthEnd(MonthOffset): Timestamp('2020-03-31 05:01:15') """ + _period_dtype_code = M _prefix = "BM" _day_opt = "business_end" From 29edef378c3939c34eb420a62658eb2e9bdc9e01 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 13:42:08 +0100 Subject: [PATCH 19/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 9858009c99711..608d95d322c7c 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2270,7 +2270,7 @@ cdef class MonthEnd(MonthOffset): DateOffset of one month end. """ - _period_dtype_code = M + _period_dtype_code = PeriodDtypeCode.M _prefix = "M" _day_opt = "end" @@ -2311,7 +2311,7 @@ cdef class BusinessMonthEnd(MonthOffset): Timestamp('2020-03-31 05:01:15') """ - _period_dtype_code = M + _period_dtype_code = PeriodDtypeCode.M _prefix = "BM" _day_opt = "business_end" From 485e60b9c0bfa8fe816e930b566ceaae1e56dbc4 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 17:35:57 +0100 Subject: [PATCH 20/64] [BUG] Breaking change to offsets.pyx - MonthOffset Add ability to use `MonthBegin`, `BMonthBegin` and `BMonthEnd` as periods, e.g., by using their offset aliases as `freq` in `date_range`. It would address #38914. --- pandas/_libs/tslibs/offsets.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 2d4704ad3bda6..771230fe794eb 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2156,6 +2156,8 @@ cdef class QuarterBegin(QuarterOffset): # Month-Based Offset Classes cdef class MonthOffset(SingleConstructorOffset): + _period_dtype_code = PeriodDtypeCode.M + def is_on_offset(self, dt: datetime) -> bool: if self.normalize and not _is_normalized(dt): return False @@ -2189,7 +2191,6 @@ cdef class MonthEnd(MonthOffset): """ DateOffset of one month end. """ - _period_dtype_code = PeriodDtypeCode.M _prefix = "M" _day_opt = "end" From 0fa3644bad22076f63c17fe93ab3b74034e57d21 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 20:29:03 +0100 Subject: [PATCH 21/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 608d95d322c7c..4bb4e4e9f53c9 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2123,10 +2123,6 @@ cdef class QuarterBegin(QuarterOffset): >>> ts = pd.Timestamp('2020-05-24 05:01:15') >>> ts + QuarterBegin()._from_name('MAR') Timestamp('2020-06-01 05:01:15') - >>> ts + QuarterBegin() - Timestamp('2020-07-01 05:01:15') - >>> ts + QuarterBegin(2) - Timestamp('2020-10-01 05:01:15') >>> ts + QuarterBegin(2, startingMonth = 2) Timestamp('2020-11-01 05:01:15') """ @@ -2135,6 +2131,17 @@ cdef class QuarterBegin(QuarterOffset): _default_month = 3 # should be 1 _prefix = "QS" _day_opt = "start" + _from_name_starting_month = 1 + + @classmethod + def _from_name(cls, suffix=None): + kwargs = {} + if suffix: + kwargs["startingMonth"] = MONTH_TO_CAL_NUM[suffix] + else: + if cls._from_name_starting_month is not None: + kwargs["startingMonth"] = cls._from_name_starting_month + return cls(**kwargs) cdef class QuarterEnd(QuarterOffset): @@ -2177,20 +2184,25 @@ cdef class BQuarterBegin(QuarterOffset): -------- >>> from pandas.tseries.offsets import BQuarterBegin >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BQuarterBegin() - Timestamp('2020-07-01 05:01:15') - >>> ts + BQuarterBegin(2) - Timestamp('2020-10-01 05:01:15') >>> ts + BQuarterBegin(startingMonth=2) Timestamp('2020-08-03 05:01:15') - >>> ts + BQuarterBegin(-1) - Timestamp('2020-04-01 05:01:15') """ _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _prefix = "BQS" _day_opt = "business_start" + _from_name_starting_month = 1 + + @classmethod + def _from_name(cls, suffix=None): + kwargs = {} + if suffix: + kwargs["startingMonth"] = MONTH_TO_CAL_NUM[suffix] + else: + if cls._from_name_starting_month is not None: + kwargs["startingMonth"] = cls._from_name_starting_month + return cls(**kwargs) cdef class BQuarterEnd(QuarterOffset): From 3456f5a5029a734729c8eed2275014fa6eb999dc Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 21:02:10 +0100 Subject: [PATCH 22/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 4bb4e4e9f53c9..4db7ec5139c2b 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2228,7 +2228,7 @@ cdef class BQuarterEnd(QuarterOffset): """ _output_name = "BusinessQuarterEnd" - _default_month = 3 + _default_month = 12 # Should be 3 _prefix = "BQ" _day_opt = "business_end" From 564cd299ecc4b754c2533656130cf005653864fe Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 21:37:29 +0100 Subject: [PATCH 23/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 4db7ec5139c2b..b5267edab4352 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2065,8 +2065,8 @@ cdef class QuarterOffset(SingleConstructorOffset): if suffix: kwargs["startingMonth"] = MONTH_TO_CAL_NUM[suffix] else: - if cls._default_month is not None: - kwargs["startingMonth"] = cls._default_month + if cls._from_name_starting_month is not None: + kwargs["startingMonth"] = cls._from_name_starting_month return cls(**kwargs) @property @@ -2129,19 +2129,9 @@ cdef class QuarterBegin(QuarterOffset): _output_name = "QuarterBegin" _default_month = 3 # should be 1 + _from_name_starting_month = 1 _prefix = "QS" _day_opt = "start" - _from_name_starting_month = 1 - - @classmethod - def _from_name(cls, suffix=None): - kwargs = {} - if suffix: - kwargs["startingMonth"] = MONTH_TO_CAL_NUM[suffix] - else: - if cls._from_name_starting_month is not None: - kwargs["startingMonth"] = cls._from_name_starting_month - return cls(**kwargs) cdef class QuarterEnd(QuarterOffset): @@ -2190,19 +2180,9 @@ cdef class BQuarterBegin(QuarterOffset): _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 + _from_name_starting_month = 1 _prefix = "BQS" _day_opt = "business_start" - _from_name_starting_month = 1 - - @classmethod - def _from_name(cls, suffix=None): - kwargs = {} - if suffix: - kwargs["startingMonth"] = MONTH_TO_CAL_NUM[suffix] - else: - if cls._from_name_starting_month is not None: - kwargs["startingMonth"] = cls._from_name_starting_month - return cls(**kwargs) cdef class BQuarterEnd(QuarterOffset): @@ -2228,7 +2208,8 @@ cdef class BQuarterEnd(QuarterOffset): """ _output_name = "BusinessQuarterEnd" - _default_month = 12 # Should be 3 + _default_month = 3 + _from_name_starting_month = 12 _prefix = "BQ" _day_opt = "business_end" From 926745d4047fc4ef4415c9c79ef8475063fabac5 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Feb 2021 22:37:45 +0100 Subject: [PATCH 24/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index b5267edab4352..2bbac51ad0756 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2201,7 +2201,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-06-30 05:01:15') >>> ts + BQuarterEnd(2) Timestamp('2020-09-30 05:01:15') - >>> ts + BQuarterEnd(1, startingMonth=2) + >>> ts + BQuarterEnd(1, startingMonth = 2) Timestamp('2020-05-29 05:01:15') >>> ts + BQuarterEnd(startingMonth=2) Timestamp('2020-05-29 05:01:15') From 4593d7295c3882f77351e2094d6d40e47aec3602 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 09:34:43 +0100 Subject: [PATCH 25/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 771230fe794eb..890e2c1304d5d 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -3471,6 +3471,8 @@ _lite_rule_alias = { "BAS": "BAS-JAN", # BYearBegin(month=1), "BYS": "BAS-JAN", + "MS": "M" + "Min": "T", "min": "T", "ms": "L", From 85c896ce6c4c5aac33101cd636777461b3e43ff6 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 09:39:04 +0100 Subject: [PATCH 26/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 890e2c1304d5d..fd3a19483f456 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -3471,7 +3471,9 @@ _lite_rule_alias = { "BAS": "BAS-JAN", # BYearBegin(month=1), "BYS": "BAS-JAN", - "MS": "M" + "MS": "M", # MonthBegin + "BMS": "M", # BusinessMonthBegin + "BM": "M", # BusinessMonthEnd "Min": "T", "min": "T", From 6654c89bc036cea85d7f6977c1ae381bd8822f1a Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 09:43:32 +0100 Subject: [PATCH 27/64] Update test_asfreq.py --- pandas/tests/scalar/period/test_asfreq.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pandas/tests/scalar/period/test_asfreq.py b/pandas/tests/scalar/period/test_asfreq.py index 9110352d33c26..2b331bea41462 100644 --- a/pandas/tests/scalar/period/test_asfreq.py +++ b/pandas/tests/scalar/period/test_asfreq.py @@ -793,12 +793,8 @@ def test_asfreq_MS(self): initial = Period("2013") assert initial.asfreq(freq="M", how="S") == Period("2013-01", "M") - - msg = INVALID_FREQ_ERR_MSG - with pytest.raises(ValueError, match=msg): - initial.asfreq(freq="MS", how="S") - - with pytest.raises(ValueError, match=msg): - Period("2013-01", "MS") + assert initial.asfreq(freq="MS", how="S") == Period("2013-01", "MS") + assert initial.asfreq(freq="M", how="S") == Period("2013-01", "MS") + assert initial.asfreq(freq="MS", how="S") == Period("2013-01", "M") assert _period_code_map.get("MS") is None From 527f70f5bd0a27c55f0a3488eb3f4ab1ccae2ddb Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 09:49:24 +0100 Subject: [PATCH 28/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index fd3a19483f456..fea34cbdd0915 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2209,13 +2209,13 @@ cdef class BusinessMonthEnd(MonthOffset): Examples -------- - >>> from pandas.tseries.offset import BMonthEnd + >>> from pandas.tseries.offsets import BusinessMonthEnd >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BMonthEnd() + >>> ts + BusinessMonthEnd() Timestamp('2020-05-29 05:01:15') - >>> ts + BMonthEnd(2) + >>> ts + BusinessMonthEnd(2) Timestamp('2020-06-30 05:01:15') - >>> ts + BMonthEnd(-2) + >>> ts + BusinessMonthEnd(-2) Timestamp('2020-03-31 05:01:15') """ _prefix = "BM" @@ -2228,13 +2228,13 @@ cdef class BusinessMonthBegin(MonthOffset): Examples -------- - >>> from pandas.tseries.offset import BMonthBegin + >>> from pandas.tseries.offsets import BusinessMonthBegin >>> ts=pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BMonthBegin() + >>> ts + BusinessMonthBegin() Timestamp('2020-06-01 05:01:15') - >>> ts + BMonthBegin(2) + >>> ts + BusinessMonthBegin(2) Timestamp('2020-07-01 05:01:15') - >>> ts + BMonthBegin(-3) + >>> ts + BusinessMonthBegin(-3) Timestamp('2020-03-02 05:01:15') """ _prefix = "BMS" From 32d61edff23f7ae0386fdbb0eeb415745c301586 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 10:13:19 +0100 Subject: [PATCH 29/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index fea34cbdd0915..a79a5816cea47 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2218,6 +2218,8 @@ cdef class BusinessMonthEnd(MonthOffset): >>> ts + BusinessMonthEnd(-2) Timestamp('2020-03-31 05:01:15') """ + + _period_dtype_code = None _prefix = "BM" _day_opt = "business_end" @@ -2237,6 +2239,8 @@ cdef class BusinessMonthBegin(MonthOffset): >>> ts + BusinessMonthBegin(-3) Timestamp('2020-03-02 05:01:15') """ + + _period_dtype_code = None _prefix = "BMS" _day_opt = "business_start" @@ -3472,8 +3476,9 @@ _lite_rule_alias = { "BYS": "BAS-JAN", "MS": "M", # MonthBegin - "BMS": "M", # BusinessMonthBegin - "BM": "M", # BusinessMonthEnd + # TODO: implement business month periods? + # "BMS": "BM", # BusinessMonthBegin + # "BM": "BM", # BusinessMonthEnd "Min": "T", "min": "T", From 63325a0a314ea3dcf7b03256a2db9ca3884f3bc0 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 11:47:40 +0100 Subject: [PATCH 30/64] Update offsets.pyx Rollback of _lite_rule_alias change. --- pandas/_libs/tslibs/offsets.pyx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index a79a5816cea47..ae8d8c3439565 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -3475,11 +3475,6 @@ _lite_rule_alias = { "BAS": "BAS-JAN", # BYearBegin(month=1), "BYS": "BAS-JAN", - "MS": "M", # MonthBegin - # TODO: implement business month periods? - # "BMS": "BM", # BusinessMonthBegin - # "BM": "BM", # BusinessMonthEnd - "Min": "T", "min": "T", "ms": "L", From 199237a07af5bde1756407bc4e9252fe2e561138 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 11:49:53 +0100 Subject: [PATCH 31/64] Update dtypes.pyx Add `"MS"` as a monthly code to `_period_code_map` --- pandas/_libs/tslibs/dtypes.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index 415bdf74db80a..f36ca20558566 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -78,6 +78,7 @@ _period_code_map = { "Q-NOV": 2011, # Quarterly - November year end "M": 3000, # Monthly + "MS": 3000, # Monthly "W-SUN": 4000, # Weekly - Sunday end of week "W-MON": 4001, # Weekly - Monday end of week From cd79bff7ba7fa413e51aa08c00c28b48d2ed97b0 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 12:06:57 +0100 Subject: [PATCH 32/64] Update test_asfreq.py --- pandas/tests/scalar/period/test_asfreq.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tests/scalar/period/test_asfreq.py b/pandas/tests/scalar/period/test_asfreq.py index 2b331bea41462..952cd6c28b911 100644 --- a/pandas/tests/scalar/period/test_asfreq.py +++ b/pandas/tests/scalar/period/test_asfreq.py @@ -791,10 +791,10 @@ def test_asfreq_combined(self): def test_asfreq_MS(self): initial = Period("2013") + ts1 = Period("2013-01", "MS").to_timestamp() + ts2 = Period("2013-01", "M").to_timestamp(how="start") assert initial.asfreq(freq="M", how="S") == Period("2013-01", "M") assert initial.asfreq(freq="MS", how="S") == Period("2013-01", "MS") - assert initial.asfreq(freq="M", how="S") == Period("2013-01", "MS") - assert initial.asfreq(freq="MS", how="S") == Period("2013-01", "M") - - assert _period_code_map.get("MS") is None + assert initial.asfreq(freq="M", how="S").to_timestamp(how="start") == ts1 + assert initial.asfreq(freq="MS", how="S").to_timestamp() == ts2 From 42c4e2632ce10197bda2f595c5bb447672489943 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 12:14:10 +0100 Subject: [PATCH 33/64] Update test_asfreq.py --- pandas/tests/scalar/period/test_asfreq.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/scalar/period/test_asfreq.py b/pandas/tests/scalar/period/test_asfreq.py index 952cd6c28b911..2ae40fcf1bb12 100644 --- a/pandas/tests/scalar/period/test_asfreq.py +++ b/pandas/tests/scalar/period/test_asfreq.py @@ -796,5 +796,6 @@ def test_asfreq_MS(self): assert initial.asfreq(freq="M", how="S") == Period("2013-01", "M") assert initial.asfreq(freq="MS", how="S") == Period("2013-01", "MS") - assert initial.asfreq(freq="M", how="S").to_timestamp(how="start") == ts1 + assert initial.asfreq(freq="M", how="S").to_timestamp(how="start") \ + == ts1 assert initial.asfreq(freq="MS", how="S").to_timestamp() == ts2 From 0ce8c021d767c6a406d2463be99553d867b41421 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 12:26:33 +0100 Subject: [PATCH 34/64] Update test_asfreq.py --- pandas/tests/scalar/period/test_asfreq.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/scalar/period/test_asfreq.py b/pandas/tests/scalar/period/test_asfreq.py index 2ae40fcf1bb12..57f48459c0603 100644 --- a/pandas/tests/scalar/period/test_asfreq.py +++ b/pandas/tests/scalar/period/test_asfreq.py @@ -791,11 +791,11 @@ def test_asfreq_combined(self): def test_asfreq_MS(self): initial = Period("2013") + ts0 = initial.asfreq(freq="M", how="S").to_timestamp(how="start") ts1 = Period("2013-01", "MS").to_timestamp() ts2 = Period("2013-01", "M").to_timestamp(how="start") assert initial.asfreq(freq="M", how="S") == Period("2013-01", "M") assert initial.asfreq(freq="MS", how="S") == Period("2013-01", "MS") - assert initial.asfreq(freq="M", how="S").to_timestamp(how="start") \ - == ts1 + assert ts0 == ts1 assert initial.asfreq(freq="MS", how="S").to_timestamp() == ts2 From 362d3d163ad68fabd1939db28e610764ec73b2e7 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 12:40:31 +0100 Subject: [PATCH 35/64] Update test_asfreq.py --- pandas/tests/scalar/period/test_asfreq.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/tests/scalar/period/test_asfreq.py b/pandas/tests/scalar/period/test_asfreq.py index 57f48459c0603..c71c5fb613966 100644 --- a/pandas/tests/scalar/period/test_asfreq.py +++ b/pandas/tests/scalar/period/test_asfreq.py @@ -1,6 +1,5 @@ import pytest -from pandas._libs.tslibs.dtypes import _period_code_map from pandas._libs.tslibs.period import INVALID_FREQ_ERR_MSG from pandas.errors import OutOfBoundsDatetime From 6f18722dc3c548af923fec8201a270a32b90686c Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 12:55:18 +0100 Subject: [PATCH 36/64] Update test_period.py --- pandas/tests/scalar/period/test_period.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/scalar/period/test_period.py b/pandas/tests/scalar/period/test_period.py index 7dcd4dc979eb2..d9794549d7e2b 100644 --- a/pandas/tests/scalar/period/test_period.py +++ b/pandas/tests/scalar/period/test_period.py @@ -220,6 +220,7 @@ def test_period_constructor_offsets(self): ) assert Period(200701, freq=offsets.MonthEnd()) == Period(200701, freq="M") + assert Period(200701, freq=offsets.MonthBegin()) == Period(200701, freq="MS") i1 = Period(ordinal=200701, freq=offsets.MonthEnd()) i2 = Period(ordinal=200701, freq="M") From 818cbdf638694990f027f950aa150f0fdf36721a Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 19:45:30 +0100 Subject: [PATCH 37/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 2bbac51ad0756..405d2c9df8f6e 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1925,8 +1925,6 @@ cdef class YearBegin(YearOffset): Timestamp('2021-01-01 05:01:15') >>> ts + YearBegin(normalize = True) Timestamp('2021-01-01 00:00:00') - >>> ts + YearBegin()._from_name('APR') - Timestamp('2021-04-01 05:01:15') """ _outputName = "YearBegin" @@ -1947,8 +1945,6 @@ cdef class YearEnd(YearOffset): Timestamp('2020-12-31 05:01:15') >>> ts + YearEnd(normalize = True) Timestamp('2020-12-31 00:00:00') - >>> ts + YearEnd()._from_name('AUG') - Timestamp('2020-08-31 05:01:15') """ _outputName = "YearEnd" @@ -1975,6 +1971,7 @@ cdef class BYearBegin(YearOffset): Timestamp('2022-01-03 05:01:15') """ + _period_dtype_code = None _outputName = "BusinessYearBegin" _default_month = 1 _prefix = "BAS" @@ -2015,6 +2012,7 @@ cdef class BYearEnd(YearOffset): Timestamp('2020-11-30 05:01:15') """ + _period_dtype_code = None _outputName = "BusinessYearEnd" _default_month = 12 _prefix = "BA" @@ -2121,8 +2119,6 @@ cdef class QuarterBegin(QuarterOffset): -------- >>> from pandas.tseries.offsets import QuarterBegin >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + QuarterBegin()._from_name('MAR') - Timestamp('2020-06-01 05:01:15') >>> ts + QuarterBegin(2, startingMonth = 2) Timestamp('2020-11-01 05:01:15') """ @@ -2148,8 +2144,6 @@ cdef class QuarterEnd(QuarterOffset): >>> ts = pd.Timestamp('2020-05-24 05:01:15') >>> ts + QuarterEnd(2) Timestamp('2020-09-30 05:01:15') - >>> ts + QuarterEnd()._from_name('JUN') - Timestamp('2020-06-30 05:01:15') >>> ts + QuarterEnd(1, normalize = True) Timestamp('2020-06-30 00:00:00') >>> ts + QuarterEnd(-2, startingMonth = 2) @@ -2178,6 +2172,7 @@ cdef class BQuarterBegin(QuarterOffset): Timestamp('2020-08-03 05:01:15') """ + _period_dtype_code = None _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _from_name_starting_month = 1 @@ -2207,6 +2202,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-05-29 05:01:15') """ + _period_dtype_code = None _output_name = "BusinessQuarterEnd" _default_month = 3 _from_name_starting_month = 12 From 1d14b0fa17920ce20df3b168d0544317a4b7819f Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 20:01:48 +0100 Subject: [PATCH 38/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 405d2c9df8f6e..d5f4f59daeba1 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2172,7 +2172,7 @@ cdef class BQuarterBegin(QuarterOffset): Timestamp('2020-08-03 05:01:15') """ - _period_dtype_code = None + self._period_dtype_code = None _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _from_name_starting_month = 1 @@ -2202,7 +2202,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-05-29 05:01:15') """ - _period_dtype_code = None + self._period_dtype_code = None _output_name = "BusinessQuarterEnd" _default_month = 3 _from_name_starting_month = 12 From 700ba0e7744d820aee350f0f2c8cfc0a31bb437a Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 20:31:55 +0100 Subject: [PATCH 39/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index d5f4f59daeba1..273aeb418ddd0 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1843,7 +1843,6 @@ cdef class YearOffset(SingleConstructorOffset): _default_month = 1 cdef: - public int _period_dtype_code readonly int month def __init__(self, n=1, normalize=False, month=None): @@ -2034,7 +2033,6 @@ cdef class QuarterOffset(SingleConstructorOffset): _default_month = 1 cdef: - public int _period_dtype_code readonly int startingMonth def __init__(self, n=1, normalize=False, startingMonth=None): @@ -2172,7 +2170,7 @@ cdef class BQuarterBegin(QuarterOffset): Timestamp('2020-08-03 05:01:15') """ - self._period_dtype_code = None + _period_dtype_code = None _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _from_name_starting_month = 1 @@ -2202,7 +2200,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-05-29 05:01:15') """ - self._period_dtype_code = None + _period_dtype_code = None _output_name = "BusinessQuarterEnd" _default_month = 3 _from_name_starting_month = 12 From 648c7a8d92f033aad3dcd862bb05539159b9d394 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 21:42:06 +0100 Subject: [PATCH 40/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 273aeb418ddd0..146be5538d904 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1840,10 +1840,11 @@ cdef class YearOffset(SingleConstructorOffset): """ _attributes = tuple(["n", "normalize", "month"]) - _default_month = 1 + # _default_month = 1 cdef: readonly int month + public int _default_month, _period_dtype_code def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) @@ -1970,7 +1971,7 @@ cdef class BYearBegin(YearOffset): Timestamp('2022-01-03 05:01:15') """ - _period_dtype_code = None + del(_period_dtype_code) _outputName = "BusinessYearBegin" _default_month = 1 _prefix = "BAS" @@ -2011,7 +2012,7 @@ cdef class BYearEnd(YearOffset): Timestamp('2020-11-30 05:01:15') """ - _period_dtype_code = None + del(_period_dtype_code) _outputName = "BusinessYearEnd" _default_month = 12 _prefix = "BA" @@ -2030,10 +2031,11 @@ cdef class QuarterOffset(SingleConstructorOffset): # startingMonth vs month attr names are resolved _attributes = tuple(["n", "normalize", "startingMonth"]) - _default_month = 1 + # _default_month = 1 cdef: readonly int startingMonth + public int _period_dtype_code, _default_month def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) @@ -2170,7 +2172,7 @@ cdef class BQuarterBegin(QuarterOffset): Timestamp('2020-08-03 05:01:15') """ - _period_dtype_code = None + del(_period_dtype_code) _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _from_name_starting_month = 1 @@ -2200,7 +2202,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-05-29 05:01:15') """ - _period_dtype_code = None + del(_period_dtype_code) _output_name = "BusinessQuarterEnd" _default_month = 3 _from_name_starting_month = 12 From fdc7e547688cadc4c3cdf62670438d4ed7194d7e Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 22:02:25 +0100 Subject: [PATCH 41/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 146be5538d904..36a121aaeadc5 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1971,7 +1971,7 @@ cdef class BYearBegin(YearOffset): Timestamp('2022-01-03 05:01:15') """ - del(_period_dtype_code) + del _period_dtype_code _outputName = "BusinessYearBegin" _default_month = 1 _prefix = "BAS" @@ -2012,7 +2012,7 @@ cdef class BYearEnd(YearOffset): Timestamp('2020-11-30 05:01:15') """ - del(_period_dtype_code) + del _period_dtype_code _outputName = "BusinessYearEnd" _default_month = 12 _prefix = "BA" @@ -2172,7 +2172,7 @@ cdef class BQuarterBegin(QuarterOffset): Timestamp('2020-08-03 05:01:15') """ - del(_period_dtype_code) + del _period_dtype_code _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _from_name_starting_month = 1 @@ -2202,7 +2202,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-05-29 05:01:15') """ - del(_period_dtype_code) + del _period_dtype_code _output_name = "BusinessQuarterEnd" _default_month = 3 _from_name_starting_month = 12 From 070cd72265b94cbeea56efb4a74dde6873d0f079 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 22:34:31 +0100 Subject: [PATCH 42/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 36a121aaeadc5..327768967a9a6 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1971,7 +1971,7 @@ cdef class BYearBegin(YearOffset): Timestamp('2022-01-03 05:01:15') """ - del _period_dtype_code + del self._period_dtype_code _outputName = "BusinessYearBegin" _default_month = 1 _prefix = "BAS" @@ -2012,7 +2012,7 @@ cdef class BYearEnd(YearOffset): Timestamp('2020-11-30 05:01:15') """ - del _period_dtype_code + del self._period_dtype_code _outputName = "BusinessYearEnd" _default_month = 12 _prefix = "BA" @@ -2172,7 +2172,7 @@ cdef class BQuarterBegin(QuarterOffset): Timestamp('2020-08-03 05:01:15') """ - del _period_dtype_code + del self._period_dtype_code _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _from_name_starting_month = 1 @@ -2202,7 +2202,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-05-29 05:01:15') """ - del _period_dtype_code + del self._period_dtype_code _output_name = "BusinessQuarterEnd" _default_month = 3 _from_name_starting_month = 12 From efb314ee67b91d4ce0f57ff89c63a475d384f955 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sat, 20 Feb 2021 23:10:09 +0100 Subject: [PATCH 43/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 327768967a9a6..7bb91cabd2d8e 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1971,7 +1971,7 @@ cdef class BYearBegin(YearOffset): Timestamp('2022-01-03 05:01:15') """ - del self._period_dtype_code + del(self._period_dtype_code) _outputName = "BusinessYearBegin" _default_month = 1 _prefix = "BAS" @@ -2012,7 +2012,7 @@ cdef class BYearEnd(YearOffset): Timestamp('2020-11-30 05:01:15') """ - del self._period_dtype_code + del(self._period_dtype_code) _outputName = "BusinessYearEnd" _default_month = 12 _prefix = "BA" @@ -2172,7 +2172,7 @@ cdef class BQuarterBegin(QuarterOffset): Timestamp('2020-08-03 05:01:15') """ - del self._period_dtype_code + del(self._period_dtype_code) _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _from_name_starting_month = 1 @@ -2202,7 +2202,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-05-29 05:01:15') """ - del self._period_dtype_code + del(self._period_dtype_code) _output_name = "BusinessQuarterEnd" _default_month = 3 _from_name_starting_month = 12 From 045177eac0b2df15a9860b71d1450ef58ff4e382 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sun, 21 Feb 2021 01:31:33 +0100 Subject: [PATCH 44/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 7bb91cabd2d8e..995435119cf3c 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1971,7 +1971,7 @@ cdef class BYearBegin(YearOffset): Timestamp('2022-01-03 05:01:15') """ - del(self._period_dtype_code) + # del(self._period_dtype_code) _outputName = "BusinessYearBegin" _default_month = 1 _prefix = "BAS" @@ -2012,7 +2012,7 @@ cdef class BYearEnd(YearOffset): Timestamp('2020-11-30 05:01:15') """ - del(self._period_dtype_code) + # del(self._period_dtype_code) _outputName = "BusinessYearEnd" _default_month = 12 _prefix = "BA" @@ -2172,7 +2172,7 @@ cdef class BQuarterBegin(QuarterOffset): Timestamp('2020-08-03 05:01:15') """ - del(self._period_dtype_code) + # del(self._period_dtype_code) _output_name = "BusinessQuarterBegin" _default_month = 3 # Should be 1 _from_name_starting_month = 1 @@ -2202,7 +2202,7 @@ cdef class BQuarterEnd(QuarterOffset): Timestamp('2020-05-29 05:01:15') """ - del(self._period_dtype_code) + # del(self._period_dtype_code) _output_name = "BusinessQuarterEnd" _default_month = 3 _from_name_starting_month = 12 From 4f15b5bfb1941c735120045870a1d104f4841ee7 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sun, 21 Feb 2021 02:03:41 +0100 Subject: [PATCH 45/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 995435119cf3c..d8f5494c50d1e 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1840,11 +1840,11 @@ cdef class YearOffset(SingleConstructorOffset): """ _attributes = tuple(["n", "normalize", "month"]) - # _default_month = 1 + _default_month = 1 cdef: readonly int month - public int _default_month, _period_dtype_code + # public int _default_month, _period_dtype_code def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) @@ -2031,11 +2031,11 @@ cdef class QuarterOffset(SingleConstructorOffset): # startingMonth vs month attr names are resolved _attributes = tuple(["n", "normalize", "startingMonth"]) - # _default_month = 1 + _default_month = 1 cdef: readonly int startingMonth - public int _period_dtype_code, _default_month + # public int _period_dtype_code, _default_month def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) From fbf3f68c9c75da1c87a6441627fa6c0ed322c881 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sun, 21 Feb 2021 02:24:57 +0100 Subject: [PATCH 46/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index d8f5494c50d1e..441da39f74252 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1843,8 +1843,8 @@ cdef class YearOffset(SingleConstructorOffset): _default_month = 1 cdef: - readonly int month - # public int _default_month, _period_dtype_code + readonly int month, _period_dtype_code + # public int _period_dtype_code def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) @@ -2034,8 +2034,8 @@ cdef class QuarterOffset(SingleConstructorOffset): _default_month = 1 cdef: - readonly int startingMonth - # public int _period_dtype_code, _default_month + readonly int startingMonth, _period_dtype_code + # public int _period_dtype_code def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) From 5f8711cb72729b83d0604fbdaeffbe736c86828f Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Wed, 17 Mar 2021 22:34:58 +0100 Subject: [PATCH 47/64] Update dtypes.pyx Add improved "MS" (month start) entry to _period_code_map --- pandas/_libs/tslibs/dtypes.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index f36ca20558566..58c1160973137 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -77,8 +77,8 @@ _period_code_map = { "Q-OCT": 2010, # Quarterly - October year end "Q-NOV": 2011, # Quarterly - November year end - "M": 3000, # Monthly - "MS": 3000, # Monthly + "M": 3000, # Monthly - month end + "MS": 3001, # Monthly - month start "W-SUN": 4000, # Weekly - Sunday end of week "W-MON": 4001, # Weekly - Monday end of week From a804a3ed2a768f2bbf9b220352a524109fafc86c Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Mar 2021 00:08:06 +0100 Subject: [PATCH 48/64] Update test_asfreq.py Parametrize and rename `test_M_vs_MS`, add `MS` tests to `test_asfreq_near_zero`, `test_conv_weekly` and `test_conv_monthly`. --- pandas/tests/scalar/period/test_asfreq.py | 36 +++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/pandas/tests/scalar/period/test_asfreq.py b/pandas/tests/scalar/period/test_asfreq.py index c71c5fb613966..36fce1eda354a 100644 --- a/pandas/tests/scalar/period/test_asfreq.py +++ b/pandas/tests/scalar/period/test_asfreq.py @@ -13,7 +13,7 @@ class TestFreqConversion: """Test frequency conversion of date objects""" - @pytest.mark.parametrize("freq", ["A", "Q", "M", "W", "B", "D"]) + @pytest.mark.parametrize("freq", ["A", "Q", "M", "MS", "W", "B", "D"]) def test_asfreq_near_zero(self, freq): # GH#19643, GH#19650 per = Period("0001-01-01", freq=freq) @@ -214,6 +214,7 @@ def test_conv_monthly(self): ival_M_to_S_end = Period( freq="S", year=2007, month=1, day=31, hour=23, minute=59, second=59 ) + ival_MS = Period(freq="MS", year=2007, month=1) assert ival_M.asfreq("A") == ival_M_to_A assert ival_M_end_of_year.asfreq("A") == ival_M_to_A @@ -234,6 +235,13 @@ def test_conv_monthly(self): assert ival_M.asfreq("S", "E") == ival_M_to_S_end assert ival_M.asfreq("M") == ival_M + assert ival_M.asfreq("M") != ival_MS + assert ival_M.asfreq("MS") == ival_MS + assert ival_M.asfreq("MS") != ival_M + assert ival_MS.asfreq("MS") == ival_MS + assert ival_MS.asfreq("MS") != ival_M + assert ival_MS.asfreq("M") == ival_M + assert ival_MS.asfreq("M") != ival_MS def test_conv_weekly(self): # frequency conversion tests: from Weekly Frequency @@ -268,6 +276,7 @@ def test_conv_weekly(self): ival_W_to_A = Period(freq="A", year=2007) ival_W_to_Q = Period(freq="Q", year=2007, quarter=1) ival_W_to_M = Period(freq="M", year=2007, month=1) + ival_W_to_MS = Period(freq="MS", year=2007, month=1) if Period(freq="D", year=2007, month=12, day=31).weekday == 6: ival_W_to_A_end_of_year = Period(freq="A", year=2007) @@ -310,6 +319,7 @@ def test_conv_weekly(self): assert ival_W_end_of_quarter.asfreq("Q") == ival_W_to_Q_end_of_quarter assert ival_W.asfreq("M") == ival_W_to_M + assert ival_W.asfreq("MS") == ival_W_to_MS assert ival_W_end_of_month.asfreq("M") == ival_W_to_M_end_of_month assert ival_W.asfreq("B", "S") == ival_W_to_B_start @@ -788,13 +798,21 @@ def test_asfreq_combined(self): assert result2.ordinal == expected.ordinal assert result2.freq == expected.freq - def test_asfreq_MS(self): - initial = Period("2013") + @pytest.mark.parametrize( + "year_month", ["2013-01", "2021-02", "2022-02", "2020-07", "2027-12"]) + def test_M_vs_MS(self, year_month): + year = year_month.split("-")[0] + initial = Period(year) ts0 = initial.asfreq(freq="M", how="S").to_timestamp(how="start") - ts1 = Period("2013-01", "MS").to_timestamp() - ts2 = Period("2013-01", "M").to_timestamp(how="start") - - assert initial.asfreq(freq="M", how="S") == Period("2013-01", "M") - assert initial.asfreq(freq="MS", how="S") == Period("2013-01", "MS") - assert ts0 == ts1 + ts1 = Period(year_month, freq="MS").to_timestamp() + ts2 = Period(year_month, freq="M").to_timestamp(how="start") + ts3 = Period(year_month, freq="M").to_timestamp() + + assert initial.asfreq(freq="M", how="S") == Period(f"{year}-01", "M") + assert initial.asfreq(freq="M", how="S") != Period(f"{year}-01", "MS") + assert initial.asfreq(freq="MS", how="S") == Period(f"{year}-01", "MS") + assert initial.asfreq(freq="MS", how="S") != Period(f"{year}-01", "M") + assert initial.asfreq(freq="MS") == Period(f"{year}-12", "MS") assert initial.asfreq(freq="MS", how="S").to_timestamp() == ts2 + assert ts0 == ts1 + assert ts1 != ts3 From 213fb664e052e777fd05a3f822740ccdad2ac716 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Mar 2021 00:18:37 +0100 Subject: [PATCH 49/64] fix formatting --- pandas/tests/scalar/period/test_asfreq.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/tests/scalar/period/test_asfreq.py b/pandas/tests/scalar/period/test_asfreq.py index 36fce1eda354a..8a15fbd5d938a 100644 --- a/pandas/tests/scalar/period/test_asfreq.py +++ b/pandas/tests/scalar/period/test_asfreq.py @@ -799,8 +799,9 @@ def test_asfreq_combined(self): assert result2.freq == expected.freq @pytest.mark.parametrize( - "year_month", ["2013-01", "2021-02", "2022-02", "2020-07", "2027-12"]) - def test_M_vs_MS(self, year_month): + "year_month", ["2013-01", "2021-02", "2022-02", "2020-07", "2027-12"] + ) + def test_asfreq_M_vs_MS(self, year_month): year = year_month.split("-")[0] initial = Period(year) ts0 = initial.asfreq(freq="M", how="S").to_timestamp(how="start") From 50ddb86fa6a40258216dee7c2f53d5dd8ae4b5fe Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 18 Mar 2021 01:11:03 +0100 Subject: [PATCH 50/64] Update test_asfreq.py Fix test_asfreq_M_vs_MS --- pandas/tests/scalar/period/test_asfreq.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pandas/tests/scalar/period/test_asfreq.py b/pandas/tests/scalar/period/test_asfreq.py index 8a15fbd5d938a..aecb95c5937f6 100644 --- a/pandas/tests/scalar/period/test_asfreq.py +++ b/pandas/tests/scalar/period/test_asfreq.py @@ -804,16 +804,13 @@ def test_asfreq_combined(self): def test_asfreq_M_vs_MS(self, year_month): year = year_month.split("-")[0] initial = Period(year) - ts0 = initial.asfreq(freq="M", how="S").to_timestamp(how="start") - ts1 = Period(year_month, freq="MS").to_timestamp() - ts2 = Period(year_month, freq="M").to_timestamp(how="start") - ts3 = Period(year_month, freq="M").to_timestamp() + ts0 = Period(year_month, freq="MS").to_timestamp() + ts1 = Period(year_month, freq="M").to_timestamp() assert initial.asfreq(freq="M", how="S") == Period(f"{year}-01", "M") assert initial.asfreq(freq="M", how="S") != Period(f"{year}-01", "MS") assert initial.asfreq(freq="MS", how="S") == Period(f"{year}-01", "MS") assert initial.asfreq(freq="MS", how="S") != Period(f"{year}-01", "M") - assert initial.asfreq(freq="MS") == Period(f"{year}-12", "MS") - assert initial.asfreq(freq="MS", how="S").to_timestamp() == ts2 + assert initial.asfreq(freq="M", how="E") == Period(f"{year}-12", "M") + assert initial.asfreq(freq="MS", how="E") == Period(f"{year}-12", "MS") assert ts0 == ts1 - assert ts1 != ts3 From 2acbd33564f9240f8514ac364417ec1596950dac Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 25 Mar 2021 14:48:45 +0100 Subject: [PATCH 51/64] Fixed "MS" code mapping in _period_code_map --- pandas/_libs/tslibs/dtypes.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index 58c1160973137..c611a792f6756 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -78,7 +78,6 @@ _period_code_map = { "Q-NOV": 2011, # Quarterly - November year end "M": 3000, # Monthly - month end - "MS": 3001, # Monthly - month start "W-SUN": 4000, # Weekly - Sunday end of week "W-MON": 4001, # Weekly - Monday end of week @@ -111,6 +110,7 @@ _period_code_map.update({ "A": 1000, # Annual "W": 4000, # Weekly "C": 5000, # Custom Business Day + "MS": 3000, # Monthly - beginning of month }) cdef set _month_names = { From 407850c127f517a6996e4a297e69895f2cd1b123 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 25 Mar 2021 21:22:48 +0100 Subject: [PATCH 52/64] Add PeriodDtypeCode to MonthBegin --- pandas/_libs/tslibs/offsets.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 6b35c97e774df..9b47c67cc0e87 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2250,6 +2250,7 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ + _period_dtype_code = PeriodDtypeCode.MS _prefix = "MS" _day_opt = "start" From 7bae3f5aba6be7cda916baa4cb0fad5e6ee5c46c Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 25 Mar 2021 21:46:31 +0100 Subject: [PATCH 53/64] Update offsets.pyx --- pandas/_libs/tslibs/offsets.pyx | 276 +++++++++++++------------------- 1 file changed, 108 insertions(+), 168 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 9b47c67cc0e87..fc7add7858528 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -1838,28 +1838,21 @@ cdef class YearOffset(SingleConstructorOffset): """ DateOffset that just needs a month. """ - _attributes = tuple(["n", "normalize", "month"]) - _default_month = 1 - cdef: - readonly int month, _period_dtype_code - # public int _period_dtype_code + # _default_month: int # FIXME: python annotation here breaks things + + cdef readonly: + int month def __init__(self, n=1, normalize=False, month=None): BaseOffset.__init__(self, n, normalize) - if month is not None: - if isinstance(month, str): - self.month = MONTH_TO_CAL_NUM[month] - elif month >= 1 and month <= 12: - self.month = month - else: - raise ValueError("Month must go from 1 to 12.") - else: - self.month = self._default_month + month = month if month is not None else self._default_month + self.month = month - self._period_dtype_code = PeriodDtypeCode.A + self.month % 12 + if month < 1 or month > 12: + raise ValueError("Month must go from 1 to 12") cpdef __setstate__(self, state): self.month = state.pop("month") @@ -1872,9 +1865,6 @@ cdef class YearOffset(SingleConstructorOffset): kwargs = {} if suffix: kwargs["month"] = MONTH_TO_CAL_NUM[suffix] - else: - if cls._default_month is not None: - kwargs["month"] = cls._default_month return cls(**kwargs) @property @@ -1913,44 +1903,30 @@ cdef class YearOffset(SingleConstructorOffset): return shifted -cdef class YearBegin(YearOffset): - """ - DateOffset increments between calendar year begin dates. - - Examples - -------- - >>> from pandas.tseries.offsets import YearBegin - >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + YearBegin() - Timestamp('2021-01-01 05:01:15') - >>> ts + YearBegin(normalize = True) - Timestamp('2021-01-01 00:00:00') - """ - - _outputName = "YearBegin" - _default_month = 1 - _prefix = "AS" - _day_opt = "start" - - -cdef class YearEnd(YearOffset): +cdef class BYearEnd(YearOffset): """ - DateOffset increments between calendar year ends. + DateOffset increments between the last business day of the year. Examples -------- - >>> from pandas.tseries.offsets import YearEnd + >>> from pandas.tseries.offset import BYearEnd >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + YearEnd() + >>> ts - BYearEnd() + Timestamp('2019-12-31 05:01:15') + >>> ts + BYearEnd() Timestamp('2020-12-31 05:01:15') - >>> ts + YearEnd(normalize = True) - Timestamp('2020-12-31 00:00:00') + >>> ts + BYearEnd(3) + Timestamp('2022-12-30 05:01:15') + >>> ts + BYearEnd(-3) + Timestamp('2017-12-29 05:01:15') + >>> ts + BYearEnd(month=11) + Timestamp('2020-11-30 05:01:15') """ - _outputName = "YearEnd" + _outputName = "BusinessYearEnd" _default_month = 12 - _prefix = "A" - _day_opt = "end" + _prefix = "BA" + _day_opt = "business_end" cdef class BYearBegin(YearOffset): @@ -1959,7 +1935,7 @@ cdef class BYearBegin(YearOffset): Examples -------- - >>> from pandas.tseries.offsets import BYearBegin + >>> from pandas.tseries.offset import BYearBegin >>> ts = pd.Timestamp('2020-05-24 05:01:15') >>> ts + BYearBegin() Timestamp('2021-01-01 05:01:15') @@ -1971,86 +1947,63 @@ cdef class BYearBegin(YearOffset): Timestamp('2022-01-03 05:01:15') """ - # del(self._period_dtype_code) _outputName = "BusinessYearBegin" _default_month = 1 _prefix = "BAS" _day_opt = "business_start" -cdef class BYearEnd(YearOffset): +cdef class YearEnd(YearOffset): + """ + DateOffset increments between calendar year ends. """ - DateOffset increments between the last business days of offset years. - Here, the year is a period of 12 consecutive calendar months - (January - December by default). The "month" parameter allows custom setting - of the final month in a year (and correspondingly - the year start month). - Parameters - ---------- - n : int, default 1 - Number of years to offset. - normalize : bool, default False - If true, the time component of the resulting date-time is converted to - 00:00:00, i.e. midnight (the start, not the end of date-time). - month : int, default 12 - The calendar month number (12 for December) of the ending month - in a custom-defined year to be used as offset. + _default_month = 12 + _prefix = "A" + _day_opt = "end" - Examples - -------- - >>> from pandas.tseries.offsets import BYearEnd - >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts - BYearEnd() - Timestamp('2019-12-31 05:01:15') - >>> ts + BYearEnd() - Timestamp('2020-12-31 05:01:15') - >>> ts + BYearEnd(3) - Timestamp('2022-12-30 05:01:15') - >>> ts + BYearEnd(-3) - Timestamp('2017-12-29 05:01:15') - >>> ts + BYearEnd(month=11) - Timestamp('2020-11-30 05:01:15') + cdef readonly: + int _period_dtype_code + + def __init__(self, n=1, normalize=False, month=None): + # Because YearEnd can be the freq for a Period, define its + # _period_dtype_code at construction for performance + YearOffset.__init__(self, n, normalize, month) + self._period_dtype_code = PeriodDtypeCode.A + self.month % 12 + + +cdef class YearBegin(YearOffset): + """ + DateOffset increments between calendar year begin dates. """ - # del(self._period_dtype_code) - _outputName = "BusinessYearEnd" - _default_month = 12 - _prefix = "BA" - _day_opt = "business_end" + _default_month = 1 + _prefix = "AS" + _day_opt = "start" # ---------------------------------------------------------------------- # Quarter-Based Offset Classes cdef class QuarterOffset(SingleConstructorOffset): - """ - The baseline quarterly DateOffset that just needs a month. - """ + _attributes = tuple(["n", "normalize", "startingMonth"]) # TODO: Consider combining QuarterOffset and YearOffset __init__ at some # point. Also apply_index, is_on_offset, rule_code if # startingMonth vs month attr names are resolved - _attributes = tuple(["n", "normalize", "startingMonth"]) - _default_month = 1 + # FIXME: python annotations here breaks things + # _default_starting_month: int + # _from_name_starting_month: int - cdef: - readonly int startingMonth, _period_dtype_code - # public int _period_dtype_code + cdef readonly: + int startingMonth def __init__(self, n=1, normalize=False, startingMonth=None): BaseOffset.__init__(self, n, normalize) - if startingMonth is not None: - if isinstance(startingMonth, str): - self.startingMonth = MONTH_TO_CAL_NUM[startingMonth] - elif startingMonth >= 1 and startingMonth <= 12: - self.startingMonth = startingMonth - else: - raise ValueError("Month must go from 1 to 12.") - else: - self.startingMonth = self._default_month - - self._period_dtype_code = PeriodDtypeCode.Q_DEC + self.startingMonth % 12 + if startingMonth is None: + startingMonth = self._default_starting_month + self.startingMonth = startingMonth cpdef __setstate__(self, state): self.startingMonth = state.pop("startingMonth") @@ -2107,53 +2060,32 @@ cdef class QuarterOffset(SingleConstructorOffset): return shifted -cdef class QuarterBegin(QuarterOffset): - """ - DateOffset increments between Quarter start dates. - - startingMonth = 1 corresponds to dates like 1/01/2007, 4/01/2007, ... - startingMonth = 2 corresponds to dates like 2/01/2007, 5/01/2007, ... - startingMonth = 3 corresponds to dates like 3/01/2007, 6/01/2007, ... - - Examples - -------- - >>> from pandas.tseries.offsets import QuarterBegin - >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + QuarterBegin(2, startingMonth = 2) - Timestamp('2020-11-01 05:01:15') - """ - - _output_name = "QuarterBegin" - _default_month = 3 # should be 1 - _from_name_starting_month = 1 - _prefix = "QS" - _day_opt = "start" - - -cdef class QuarterEnd(QuarterOffset): +cdef class BQuarterEnd(QuarterOffset): """ - DateOffset increments between Quarter end dates. + DateOffset increments between the last business day of each Quarter. startingMonth = 1 corresponds to dates like 1/31/2007, 4/30/2007, ... startingMonth = 2 corresponds to dates like 2/28/2007, 5/31/2007, ... - startingMonth = 3 corresponds to dates like 3/31/2007, 6/30/2007, ... + startingMonth = 3 corresponds to dates like 3/30/2007, 6/29/2007, ... Examples -------- - >>> from pandas.tseries.offsets import QuarterEnd + >>> from pandas.tseries.offset import BQuarterEnd >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + QuarterEnd(2) + >>> ts + BQuarterEnd() + Timestamp('2020-06-30 05:01:15') + >>> ts + BQuarterEnd(2) Timestamp('2020-09-30 05:01:15') - >>> ts + QuarterEnd(1, normalize = True) - Timestamp('2020-06-30 00:00:00') - >>> ts + QuarterEnd(-2, startingMonth = 2) - Timestamp('2019-11-30 05:01:15') + >>> ts + BQuarterEnd(1, startingMonth=2) + Timestamp('2020-05-29 05:01:15') + >>> ts + BQuarterEnd(startingMonth=2) + Timestamp('2020-05-29 05:01:15') """ - - _output_name = "QuarterEnd" - _default_month = 3 - _prefix = "Q" - _day_opt = "end" + _output_name = "BusinessQuarterEnd" + _default_starting_month = 3 + _from_name_starting_month = 12 + _prefix = "BQ" + _day_opt = "business_end" cdef class BQuarterBegin(QuarterOffset): @@ -2166,48 +2098,58 @@ cdef class BQuarterBegin(QuarterOffset): Examples -------- - >>> from pandas.tseries.offsets import BQuarterBegin + >>> from pandas.tseries.offset import BQuarterBegin >>> ts = pd.Timestamp('2020-05-24 05:01:15') + >>> ts + BQuarterBegin() + Timestamp('2020-06-01 05:01:15') + >>> ts + BQuarterBegin(2) + Timestamp('2020-09-01 05:01:15') >>> ts + BQuarterBegin(startingMonth=2) Timestamp('2020-08-03 05:01:15') + >>> ts + BQuarterBegin(-1) + Timestamp('2020-03-02 05:01:15') """ - - # del(self._period_dtype_code) _output_name = "BusinessQuarterBegin" - _default_month = 3 # Should be 1 + _default_starting_month = 3 _from_name_starting_month = 1 _prefix = "BQS" _day_opt = "business_start" -cdef class BQuarterEnd(QuarterOffset): +cdef class QuarterEnd(QuarterOffset): """ - DateOffset increments between the last business day of each Quarter. + DateOffset increments between Quarter end dates. startingMonth = 1 corresponds to dates like 1/31/2007, 4/30/2007, ... startingMonth = 2 corresponds to dates like 2/28/2007, 5/31/2007, ... - startingMonth = 3 corresponds to dates like 3/30/2007, 6/29/2007, ... + startingMonth = 3 corresponds to dates like 3/31/2007, 6/30/2007, ... + """ + _default_starting_month = 3 + _prefix = "Q" + _day_opt = "end" - Examples - -------- - >>> from pandas.tseries.offsets import BQuarterEnd - >>> ts = pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BQuarterEnd() - Timestamp('2020-06-30 05:01:15') - >>> ts + BQuarterEnd(2) - Timestamp('2020-09-30 05:01:15') - >>> ts + BQuarterEnd(1, startingMonth = 2) - Timestamp('2020-05-29 05:01:15') - >>> ts + BQuarterEnd(startingMonth=2) - Timestamp('2020-05-29 05:01:15') + cdef readonly: + int _period_dtype_code + + def __init__(self, n=1, normalize=False, startingMonth=None): + # Because QuarterEnd can be the freq for a Period, define its + # _period_dtype_code at construction for performance + QuarterOffset.__init__(self, n, normalize, startingMonth) + self._period_dtype_code = PeriodDtypeCode.Q_DEC + self.startingMonth % 12 + + +cdef class QuarterBegin(QuarterOffset): """ + DateOffset increments between Quarter start dates. - # del(self._period_dtype_code) - _output_name = "BusinessQuarterEnd" - _default_month = 3 - _from_name_starting_month = 12 - _prefix = "BQ" - _day_opt = "business_end" + startingMonth = 1 corresponds to dates like 1/01/2007, 4/01/2007, ... + startingMonth = 2 corresponds to dates like 2/01/2007, 5/01/2007, ... + startingMonth = 3 corresponds to dates like 3/01/2007, 6/01/2007, ... + """ + _default_starting_month = 3 + _from_name_starting_month = 1 + _prefix = "QS" + _day_opt = "start" # ---------------------------------------------------------------------- @@ -2280,6 +2222,8 @@ cdef class BusinessMonthBegin(MonthOffset): >>> ts + BMonthBegin(-3) Timestamp('2020-03-02 05:01:15') """ + + _prefix = "BMS" _day_opt = "business_start" @@ -2300,8 +2244,6 @@ cdef class BusinessMonthEnd(MonthOffset): >>> ts + BusinessMonthEnd(-2) Timestamp('2020-03-31 05:01:15') """ - - _period_dtype_code = PeriodDtypeCode.M _prefix = "BM" _day_opt = "business_end" @@ -2321,8 +2263,6 @@ cdef class BusinessMonthBegin(MonthOffset): >>> ts + BusinessMonthBegin(-3) Timestamp('2020-03-02 05:01:15') """ - - _period_dtype_code = None _prefix = "BMS" _day_opt = "business_start" From 1c1fd3a8edb7a59d9d947eb845fce65a6379427e Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 25 Mar 2021 21:56:04 +0100 Subject: [PATCH 54/64] Fix MonthBegin PeriodDtypeCode --- pandas/_libs/tslibs/offsets.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index fc7add7858528..f057fc2dbf2d4 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2192,7 +2192,7 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ - _period_dtype_code = PeriodDtypeCode.MS + _period_dtype_code = PeriodDtypeCode.M _prefix = "MS" _day_opt = "start" From e519610dc26c4659f89f1a33e6d7563e3efaf873 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 25 Mar 2021 22:29:50 +0100 Subject: [PATCH 55/64] Bug hunt --- pandas/_libs/tslibs/offsets.pyx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index f057fc2dbf2d4..df7205d2d0b19 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2192,7 +2192,7 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ - _period_dtype_code = PeriodDtypeCode.M + # _period_dtype_code = PeriodDtypeCode.M _prefix = "MS" _day_opt = "start" @@ -2222,8 +2222,6 @@ cdef class BusinessMonthBegin(MonthOffset): >>> ts + BMonthBegin(-3) Timestamp('2020-03-02 05:01:15') """ - - _prefix = "BMS" _day_opt = "business_start" From c5a69b2d8d7e36908b92b680715d1de99e6effd5 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Thu, 25 Mar 2021 22:38:35 +0100 Subject: [PATCH 56/64] Remove double BusinessMonthBegin --- pandas/_libs/tslibs/offsets.pyx | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index df7205d2d0b19..8de885ee78306 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2192,7 +2192,7 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ - # _period_dtype_code = PeriodDtypeCode.M + _period_dtype_code = PeriodDtypeCode.M _prefix = "MS" _day_opt = "start" @@ -2213,13 +2213,13 @@ cdef class BusinessMonthBegin(MonthOffset): Examples -------- - >>> from pandas.tseries.offset import BMonthBegin + >>> from pandas.tseries.offsets import BusinessMonthBegin >>> ts=pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BMonthBegin() + >>> ts + BusinessMonthBegin() Timestamp('2020-06-01 05:01:15') - >>> ts + BMonthBegin(2) + >>> ts + BusinessMonthBegin(2) Timestamp('2020-07-01 05:01:15') - >>> ts + BMonthBegin(-3) + >>> ts + BusinessMonthBegin(-3) Timestamp('2020-03-02 05:01:15') """ @@ -2242,29 +2242,11 @@ cdef class BusinessMonthEnd(MonthOffset): >>> ts + BusinessMonthEnd(-2) Timestamp('2020-03-31 05:01:15') """ + _prefix = "BM" _day_opt = "business_end" -cdef class BusinessMonthBegin(MonthOffset): - """ - DateOffset of one month at the first business day. - - Examples - -------- - >>> from pandas.tseries.offsets import BusinessMonthBegin - >>> ts=pd.Timestamp('2020-05-24 05:01:15') - >>> ts + BusinessMonthBegin() - Timestamp('2020-06-01 05:01:15') - >>> ts + BusinessMonthBegin(2) - Timestamp('2020-07-01 05:01:15') - >>> ts + BusinessMonthBegin(-3) - Timestamp('2020-03-02 05:01:15') - """ - _prefix = "BMS" - _day_opt = "business_start" - - # --------------------------------------------------------------------- # Semi-Month Based Offsets From 0628d22d7fb04b3632a326a7384d11a1ac91fa57 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Tue, 30 Mar 2021 18:07:21 +0200 Subject: [PATCH 57/64] Coverage bug hunt Alter _period_code_map --- pandas/_libs/tslibs/dtypes.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index c611a792f6756..675a936577cc4 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -78,6 +78,7 @@ _period_code_map = { "Q-NOV": 2011, # Quarterly - November year end "M": 3000, # Monthly - month end + "MS": 3000, # Monthly - beginning of month "W-SUN": 4000, # Weekly - Sunday end of week "W-MON": 4001, # Weekly - Monday end of week @@ -110,7 +111,7 @@ _period_code_map.update({ "A": 1000, # Annual "W": 4000, # Weekly "C": 5000, # Custom Business Day - "MS": 3000, # Monthly - beginning of month + # "MS": 3000, # Monthly - beginning of month }) cdef set _month_names = { From ff98362a22e3bf7fffe3c5126c2c264e96b264f9 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Tue, 30 Mar 2021 19:23:52 +0200 Subject: [PATCH 58/64] Revert "Coverage bug hunt" This reverts commit 0628d22d7fb04b3632a326a7384d11a1ac91fa57. --- pandas/_libs/tslibs/dtypes.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index 675a936577cc4..c611a792f6756 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -78,7 +78,6 @@ _period_code_map = { "Q-NOV": 2011, # Quarterly - November year end "M": 3000, # Monthly - month end - "MS": 3000, # Monthly - beginning of month "W-SUN": 4000, # Weekly - Sunday end of week "W-MON": 4001, # Weekly - Monday end of week @@ -111,7 +110,7 @@ _period_code_map.update({ "A": 1000, # Annual "W": 4000, # Weekly "C": 5000, # Custom Business Day - # "MS": 3000, # Monthly - beginning of month + "MS": 3000, # Monthly - beginning of month }) cdef set _month_names = { From 56be0c9efe0679b980e54051d63892e23b6b886d Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Tue, 30 Mar 2021 21:32:13 +0200 Subject: [PATCH 59/64] Bug hunt --- pandas/_libs/tslibs/offsets.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 8de885ee78306..39adf98772ec2 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2192,7 +2192,7 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ - _period_dtype_code = PeriodDtypeCode.M + _period_dtype_code = PeriodDtypeCode.MS _prefix = "MS" _day_opt = "start" From 5303ff99a70190606c603200bc5008f4d7b8ab42 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Tue, 30 Mar 2021 21:36:41 +0200 Subject: [PATCH 60/64] Revert "Bug hunt" This reverts commit 56be0c9efe0679b980e54051d63892e23b6b886d. --- pandas/_libs/tslibs/offsets.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 39adf98772ec2..8de885ee78306 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -2192,7 +2192,7 @@ cdef class MonthBegin(MonthOffset): DateOffset of one month at beginning. """ - _period_dtype_code = PeriodDtypeCode.MS + _period_dtype_code = PeriodDtypeCode.M _prefix = "MS" _day_opt = "start" From 8aa0d8f002e308d3b37c801de66cca7965996053 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Fri, 23 Apr 2021 08:59:14 +0200 Subject: [PATCH 61/64] retrigger checks From cfa29723578ab83ff52fdb0a42a40d885b11da87 Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Fri, 23 Apr 2021 14:20:30 +0200 Subject: [PATCH 62/64] Update v1.3.0.rst --- doc/source/whatsnew/v1.3.0.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 1e723493a4cc8..a96b6671dbf65 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -145,6 +145,7 @@ Other enhancements - :class:`RangeIndex` can now be constructed by passing a ``range`` object directly e.g. ``pd.RangeIndex(range(3))`` (:issue:`12067`) - :meth:`round` being enabled for the nullable integer and floating dtypes (:issue:`38844`) - :meth:`pandas.read_csv` and :meth:`pandas.read_json` expose the argument ``encoding_errors`` to control how encoding errors are handled (:issue:`39450`) +- Date offset :class:`MonthBegin` can now be used as a period (:issue:`38859`) .. --------------------------------------------------------------------------- @@ -632,7 +633,7 @@ I/O Period ^^^^^^ - Comparisons of :class:`Period` objects or :class:`Index`, :class:`Series`, or :class:`DataFrame` with mismatched ``PeriodDtype`` now behave like other mismatched-type comparisons, returning ``False`` for equals, ``True`` for not-equal, and raising ``TypeError`` for inequality checks (:issue:`39274`) -- +- Timestamp.to_period() fails for freq="MS" (:issue:`38914`) - Plotting From 118f422bb4eae25d1747ef56c24dcbbd02f4439d Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Fri, 23 Apr 2021 14:28:38 +0200 Subject: [PATCH 63/64] Update v1.3.0.rst --- doc/source/whatsnew/v1.3.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index a7ca6c7de3309..cbd3b39a9a0f7 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -225,6 +225,7 @@ Other enhancements - Constructing a :class:`DataFrame` or :class:`Series` with the ``data`` argument being a Python iterable that is *not* a NumPy ``ndarray`` consisting of NumPy scalars will now result in a dtype with a precision the maximum of the NumPy scalars; this was already the case when ``data`` is a NumPy ``ndarray`` (:issue:`40908`) - Add keyword ``sort`` to :func:`pivot_table` to allow non-sorting of the result (:issue:`39143`) - Date offset :class:`MonthBegin` can now be used as a period (:issue:`38859`) +- .. --------------------------------------------------------------------------- From 8da61dc2e2f360b52f5b754964b066e1f663f03c Mon Sep 17 00:00:00 2001 From: Pawel Kranzberg Date: Sun, 25 Apr 2021 17:02:03 +0200 Subject: [PATCH 64/64] retrigger checks