Skip to content

Commit 0021d24

Browse files
authored
DEPR: rename ‘BM’/‘CBM’ to ‘BME’/‘CBME’ for offsets (#55496)
* rename BM, CBM to BME, CBME for offsets * fix tests * correct docs * add tests, add notes to 2.2.0 whatsnew
1 parent b5b8be0 commit 0021d24

File tree

17 files changed

+68
-37
lines changed

17 files changed

+68
-37
lines changed

doc/source/user_guide/timeseries.rst

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ of those specified will not be generated:
461461

462462
.. ipython:: python
463463
464-
pd.date_range(start, end, freq="BM")
464+
pd.date_range(start, end, freq="BME")
465465
466466
pd.date_range(start, end, freq="W")
467467
@@ -557,7 +557,7 @@ intelligent functionality like selection, slicing, etc.
557557

558558
.. ipython:: python
559559
560-
rng = pd.date_range(start, end, freq="BM")
560+
rng = pd.date_range(start, end, freq="BME")
561561
ts = pd.Series(np.random.randn(len(rng)), index=rng)
562562
ts.index
563563
ts[:5].index
@@ -884,9 +884,9 @@ into ``freq`` keyword arguments. The available date offsets and associated frequ
884884
:class:`~pandas.tseries.offsets.LastWeekOfMonth`, ``'LWOM'``, "the x-th day of the last week of each month"
885885
:class:`~pandas.tseries.offsets.MonthEnd`, ``'ME'``, "calendar month end"
886886
:class:`~pandas.tseries.offsets.MonthBegin`, ``'MS'``, "calendar month begin"
887-
:class:`~pandas.tseries.offsets.BMonthEnd` or :class:`~pandas.tseries.offsets.BusinessMonthEnd`, ``'BM'``, "business month end"
887+
:class:`~pandas.tseries.offsets.BMonthEnd` or :class:`~pandas.tseries.offsets.BusinessMonthEnd`, ``'BME'``, "business month end"
888888
:class:`~pandas.tseries.offsets.BMonthBegin` or :class:`~pandas.tseries.offsets.BusinessMonthBegin`, ``'BMS'``, "business month begin"
889-
:class:`~pandas.tseries.offsets.CBMonthEnd` or :class:`~pandas.tseries.offsets.CustomBusinessMonthEnd`, ``'CBM'``, "custom business month end"
889+
:class:`~pandas.tseries.offsets.CBMonthEnd` or :class:`~pandas.tseries.offsets.CustomBusinessMonthEnd`, ``'CBME'``, "custom business month end"
890890
:class:`~pandas.tseries.offsets.CBMonthBegin` or :class:`~pandas.tseries.offsets.CustomBusinessMonthBegin`, ``'CBMS'``, "custom business month begin"
891891
:class:`~pandas.tseries.offsets.SemiMonthEnd`, ``'SM'``, "15th (or other day_of_month) and calendar month end"
892892
:class:`~pandas.tseries.offsets.SemiMonthBegin`, ``'SMS'``, "15th (or other day_of_month) and calendar month begin"
@@ -1248,8 +1248,8 @@ frequencies. We will refer to these aliases as *offset aliases*.
12481248
"W", "weekly frequency"
12491249
"ME", "month end frequency"
12501250
"SM", "semi-month end frequency (15th and end of month)"
1251-
"BM", "business month end frequency"
1252-
"CBM", "custom business month end frequency"
1251+
"BME", "business month end frequency"
1252+
"CBME", "custom business month end frequency"
12531253
"MS", "month start frequency"
12541254
"SMS", "semi-month start frequency (1st and 15th)"
12551255
"BMS", "business month start frequency"
@@ -1586,7 +1586,7 @@ rather than changing the alignment of the data and the index:
15861586
15871587
ts.shift(5, freq="D")
15881588
ts.shift(5, freq=pd.offsets.BDay())
1589-
ts.shift(5, freq="BM")
1589+
ts.shift(5, freq="BME")
15901590
15911591
Note that with when ``freq`` is specified, the leading entry is no longer NaN
15921592
because the data is not being realigned.
@@ -1692,7 +1692,7 @@ the end of the interval.
16921692
.. warning::
16931693

16941694
The default values for ``label`` and ``closed`` is '**left**' for all
1695-
frequency offsets except for 'ME', 'Y', 'Q', 'BM', 'BY', 'BQ', and 'W'
1695+
frequency offsets except for 'ME', 'Y', 'Q', 'BME', 'BY', 'BQ', and 'W'
16961696
which all have a default of 'right'.
16971697

16981698
This might unintendedly lead to looking ahead, where the value for a later

doc/source/whatsnew/v2.2.0.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,11 @@ Other Deprecations
253253
- Deprecated downcasting behavior in :meth:`Series.where`, :meth:`DataFrame.where`, :meth:`Series.mask`, :meth:`DataFrame.mask`, :meth:`Series.clip`, :meth:`DataFrame.clip`; in a future version these will not infer object-dtype columns to non-object dtype, or all-round floats to integer dtype. Call ``result.infer_objects(copy=False)`` on the result for object inference, or explicitly cast floats to ints. To opt in to the future version, use ``pd.set_option("future.no_silent_downcasting", True)`` (:issue:`53656`)
254254
- Deprecated including the groups in computations when using :meth:`DataFrameGroupBy.apply` and :meth:`DataFrameGroupBy.resample`; pass ``include_groups=False`` to exclude the groups (:issue:`7155`)
255255
- Deprecated not passing a tuple to :class:`DataFrameGroupBy.get_group` or :class:`SeriesGroupBy.get_group` when grouping by a length-1 list-like (:issue:`25971`)
256-
- Deprecated string ``A`` denoting frequency in :class:`YearEnd` and strings ``A-DEC``, ``A-JAN``, etc. denoting annual frequencies with various fiscal year ends (:issue:`52536`)
256+
- Deprecated string ``AS`` denoting frequency in :class:`YearBegin` and strings ``AS-DEC``, ``AS-JAN``, etc. denoting annual frequencies with various fiscal year starts (:issue:`54275`)
257+
- Deprecated string ``A`` denoting frequency in :class:`YearEnd` and strings ``A-DEC``, ``A-JAN``, etc. denoting annual frequencies with various fiscal year ends (:issue:`54275`)
258+
- Deprecated string ``BAS`` denoting frequency in :class:`BYearBegin` and strings ``BAS-DEC``, ``BAS-JAN``, etc. denoting annual frequencies with various fiscal year starts (:issue:`54275`)
259+
- Deprecated string ``BA`` denoting frequency in :class:`BYearEnd` and strings ``BA-DEC``, ``BA-JAN``, etc. denoting annual frequencies with various fiscal year ends (:issue:`54275`)
260+
- Deprecated strings ``BM``, and ``CBM`` denoting frequencies in :class:`BusinessMonthEnd`, :class:`CustomBusinessMonthEnd` (:issue:`52064`)
257261
- Deprecated strings ``H``, ``BH``, and ``CBH`` denoting frequencies in :class:`Hour`, :class:`BusinessHour`, :class:`CustomBusinessHour` (:issue:`52536`)
258262
- Deprecated strings ``H``, ``S``, ``U``, and ``N`` denoting units in :func:`to_timedelta` (:issue:`52536`)
259263
- Deprecated strings ``H``, ``T``, ``S``, ``L``, ``U``, and ``N`` denoting units in :class:`Timedelta` (:issue:`52536`)

pandas/_libs/tslibs/dtypes.pyx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ cdef dict _abbrev_to_attrnames = {v: k for k, v in attrname_to_abbrevs.items()}
188188
OFFSET_TO_PERIOD_FREQSTR: dict = {
189189
"WEEKDAY": "D",
190190
"EOM": "M",
191-
"BM": "M",
191+
"BME": "M",
192192
"BQS": "Q",
193193
"QS": "Q",
194194
"BQ": "Q",
@@ -280,6 +280,8 @@ DEPR_ABBREVS: dict[str, str]= {
280280
"BAS-SEP": "BYS-SEP",
281281
"BAS-OCT": "BYS-OCT",
282282
"BAS-NOV": "BYS-NOV",
283+
"BM": "BME",
284+
"CBM": "CBME",
283285
"H": "h",
284286
"BH": "bh",
285287
"CBH": "cbh",

pandas/_libs/tslibs/offsets.pyx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,7 +2935,7 @@ cdef class BusinessMonthEnd(MonthOffset):
29352935
>>> pd.offsets.BMonthEnd().rollforward(ts)
29362936
Timestamp('2022-11-30 00:00:00')
29372937
"""
2938-
_prefix = "BM"
2938+
_prefix = "BME"
29392939
_day_opt = "business_end"
29402940

29412941

@@ -4465,10 +4465,10 @@ cdef class CustomBusinessMonthEnd(_CustomBusinessMonth):
44654465
>>> freq = pd.offsets.CustomBusinessMonthEnd(calendar=bdc)
44664466
>>> pd.date_range(dt.datetime(2022, 7, 10), dt.datetime(2022, 11, 10), freq=freq)
44674467
DatetimeIndex(['2022-07-29', '2022-08-31', '2022-09-29', '2022-10-28'],
4468-
dtype='datetime64[ns]', freq='CBM')
4468+
dtype='datetime64[ns]', freq='CBME')
44694469
"""
44704470

4471-
_prefix = "CBM"
4471+
_prefix = "CBME"
44724472

44734473

44744474
cdef class CustomBusinessMonthBegin(_CustomBusinessMonth):
@@ -4551,12 +4551,12 @@ prefix_mapping = {
45514551
BYearEnd, # 'BY'
45524552
BusinessDay, # 'B'
45534553
BusinessMonthBegin, # 'BMS'
4554-
BusinessMonthEnd, # 'BM'
4554+
BusinessMonthEnd, # 'BME'
45554555
BQuarterEnd, # 'BQ'
45564556
BQuarterBegin, # 'BQS'
45574557
BusinessHour, # 'bh'
45584558
CustomBusinessDay, # 'C'
4559-
CustomBusinessMonthEnd, # 'CBM'
4559+
CustomBusinessMonthEnd, # 'CBME'
45604560
CustomBusinessMonthBegin, # 'CBMS'
45614561
CustomBusinessHour, # 'cbh'
45624562
MonthEnd, # 'ME'

pandas/core/generic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9187,11 +9187,11 @@ def resample(
91879187
Use frame.T.resample(...) instead.
91889188
closed : {{'right', 'left'}}, default None
91899189
Which side of bin interval is closed. The default is 'left'
9190-
for all frequency offsets except for 'ME', 'Y', 'Q', 'BM',
9190+
for all frequency offsets except for 'ME', 'Y', 'Q', 'BME',
91919191
'BA', 'BQ', and 'W' which all have a default of 'right'.
91929192
label : {{'right', 'left'}}, default None
91939193
Which bin edge label to label bucket with. The default is 'left'
9194-
for all frequency offsets except for 'ME', 'Y', 'Q', 'BM',
9194+
for all frequency offsets except for 'ME', 'Y', 'Q', 'BME',
91959195
'BA', 'BQ', and 'W' which all have a default of 'right'.
91969196
convention : {{'start', 'end', 's', 'e'}}, default 'start'
91979197
For `PeriodIndex` only, controls whether to use the start or

pandas/core/resample.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,7 +2101,7 @@ def __init__(
21012101
else:
21022102
freq = to_offset(freq)
21032103

2104-
end_types = {"ME", "Y", "Q", "BM", "BY", "BQ", "W"}
2104+
end_types = {"ME", "Y", "Q", "BME", "BY", "BQ", "W"}
21052105
rule = freq.rule_code
21062106
if rule in end_types or ("-" in rule and rule[: rule.find("-")] in end_types):
21072107
if closed is None:
@@ -2297,7 +2297,7 @@ def _adjust_bin_edges(
22972297
) -> tuple[DatetimeIndex, npt.NDArray[np.int64]]:
22982298
# Some hacks for > daily data, see #1471, #1458, #1483
22992299

2300-
if self.freq.name in ("BM", "ME", "W") or self.freq.name.split("-")[0] in (
2300+
if self.freq.name in ("BME", "ME", "W") or self.freq.name.split("-")[0] in (
23012301
"BQ",
23022302
"BY",
23032303
"Q",

pandas/tests/frame/methods/test_asfreq.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@ def test_asfreq2(self, frame_or_series):
3232
datetime(2009, 11, 30),
3333
datetime(2009, 12, 31),
3434
],
35-
freq="BM",
35+
freq="BME",
3636
),
3737
)
3838

3939
daily_ts = ts.asfreq("B")
40-
monthly_ts = daily_ts.asfreq("BM")
40+
monthly_ts = daily_ts.asfreq("BME")
4141
tm.assert_equal(monthly_ts, ts)
4242

4343
daily_ts = ts.asfreq("B", method="pad")
44-
monthly_ts = daily_ts.asfreq("BM")
44+
monthly_ts = daily_ts.asfreq("BME")
4545
tm.assert_equal(monthly_ts, ts)
4646

4747
daily_ts = ts.asfreq(offsets.BDay())
@@ -140,12 +140,12 @@ def test_asfreq_resample_set_correct_freq(self, frame_or_series):
140140
def test_asfreq_empty(self, datetime_frame):
141141
# test does not blow up on length-0 DataFrame
142142
zero_length = datetime_frame.reindex([])
143-
result = zero_length.asfreq("BM")
143+
result = zero_length.asfreq("BME")
144144
assert result is not zero_length
145145

146146
def test_asfreq(self, datetime_frame):
147147
offset_monthly = datetime_frame.asfreq(offsets.BMonthEnd())
148-
rule_monthly = datetime_frame.asfreq("BM")
148+
rule_monthly = datetime_frame.asfreq("BME")
149149

150150
tm.assert_frame_equal(offset_monthly, rule_monthly)
151151

pandas/tests/indexes/datetimes/methods/test_shift.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,6 @@ def test_shift_bmonth(self):
157157

158158
def test_shift_empty(self):
159159
# GH#14811
160-
dti = date_range(start="2016-10-21", end="2016-10-21", freq="BM")
160+
dti = date_range(start="2016-10-21", end="2016-10-21", freq="BME")
161161
result = dti.shift(1)
162162
tm.assert_index_equal(result, dti)

pandas/tests/indexes/datetimes/methods/test_to_period.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_to_period_annualish(self, off):
6363
assert prng.freq == "Y-DEC"
6464

6565
def test_to_period_monthish(self):
66-
offsets = ["MS", "BM"]
66+
offsets = ["MS", "BME"]
6767
for off in offsets:
6868
rng = date_range("01-Jan-2012", periods=8, freq=off)
6969
prng = rng.to_period()

pandas/tests/indexes/datetimes/test_datetime.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,17 @@ def test_AS_BA_BAS_deprecated(self, freq_depr, expected_values, expected_freq):
264264
)
265265

266266
tm.assert_index_equal(result, expected)
267+
268+
def test_BM_deprecated(self):
269+
# GH#52064
270+
msg = "'BM' is deprecated and will be removed in a future version."
271+
272+
with tm.assert_produces_warning(FutureWarning, match=msg):
273+
expected = date_range(start="2016-02-21", end="2016-08-21", freq="2BM")
274+
result = DatetimeIndex(
275+
["2016-02-29", "2016-04-29", "2016-06-30"],
276+
dtype="datetime64[ns]",
277+
freq="2BME",
278+
)
279+
280+
tm.assert_index_equal(result, expected)

0 commit comments

Comments
 (0)