Skip to content

DEPR offsets: rename ‘Y’ to ‘YE' #55792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Nov 9, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions doc/source/user_guide/timeseries.rst
Original file line number Diff line number Diff line change
@@ -889,7 +889,7 @@ into ``freq`` keyword arguments. The available date offsets and associated frequ
:class:`~pandas.tseries.offsets.BQuarterEnd`, ``'BQ``, "business quarter end"
:class:`~pandas.tseries.offsets.BQuarterBegin`, ``'BQS'``, "business quarter begin"
:class:`~pandas.tseries.offsets.FY5253Quarter`, ``'REQ'``, "retail (aka 52-53 week) quarter"
:class:`~pandas.tseries.offsets.YearEnd`, ``'Y'``, "calendar year end"
:class:`~pandas.tseries.offsets.YearEnd`, ``'YE'``, "calendar year end"
:class:`~pandas.tseries.offsets.YearBegin`, ``'YS'`` or ``'BYS'``,"calendar year begin"
:class:`~pandas.tseries.offsets.BYearEnd`, ``'BY'``, "business year end"
:class:`~pandas.tseries.offsets.BYearBegin`, ``'BYS'``, "business year begin"
@@ -1252,7 +1252,7 @@ frequencies. We will refer to these aliases as *offset aliases*.
"BQ", "business quarter end frequency"
"QS", "quarter start frequency"
"BQS", "business quarter start frequency"
"Y", "year end frequency"
"YE", "year end frequency"
"BY", "business year end frequency"
"YS", "year start frequency"
"BYS", "business year start frequency"
@@ -1379,18 +1379,18 @@ For some frequencies you can specify an anchoring suffix:
"(B)Q(E)(S)\-SEP", "quarterly frequency, year ends in September"
"(B)Q(E)(S)\-OCT", "quarterly frequency, year ends in October"
"(B)Q(E)(S)\-NOV", "quarterly frequency, year ends in November"
"(B)Y(S)\-DEC", "annual frequency, anchored end of December. Same as 'Y'"
"(B)Y(S)\-JAN", "annual frequency, anchored end of January"
"(B)Y(S)\-FEB", "annual frequency, anchored end of February"
"(B)Y(S)\-MAR", "annual frequency, anchored end of March"
"(B)Y(S)\-APR", "annual frequency, anchored end of April"
"(B)Y(S)\-MAY", "annual frequency, anchored end of May"
"(B)Y(S)\-JUN", "annual frequency, anchored end of June"
"(B)Y(S)\-JUL", "annual frequency, anchored end of July"
"(B)Y(S)\-AUG", "annual frequency, anchored end of August"
"(B)Y(S)\-SEP", "annual frequency, anchored end of September"
"(B)Y(S)\-OCT", "annual frequency, anchored end of October"
"(B)Y(S)\-NOV", "annual frequency, anchored end of November"
"(B)Y(E)(S)\-DEC", "annual frequency, anchored end of December. Same as 'YE'"
"(B)Y(E)(S)\-JAN", "annual frequency, anchored end of January"
"(B)Y(E)(S)\-FEB", "annual frequency, anchored end of February"
"(B)Y(E)(S)\-MAR", "annual frequency, anchored end of March"
"(B)Y(E)(S)\-APR", "annual frequency, anchored end of April"
"(B)Y(E)(S)\-MAY", "annual frequency, anchored end of May"
"(B)Y(E)(S)\-JUN", "annual frequency, anchored end of June"
"(B)Y(E)(S)\-JUL", "annual frequency, anchored end of July"
"(B)Y(E)(S)\-AUG", "annual frequency, anchored end of August"
"(B)Y(E)(S)\-SEP", "annual frequency, anchored end of September"
"(B)Y(E)(S)\-OCT", "annual frequency, anchored end of October"
"(B)Y(E)(S)\-NOV", "annual frequency, anchored end of November"

These can be used as arguments to ``date_range``, ``bdate_range``, constructors
for ``DatetimeIndex``, as well as various other timeseries-related functions
@@ -1686,7 +1686,7 @@ the end of the interval.
.. warning::

The default values for ``label`` and ``closed`` is '**left**' for all
frequency offsets except for 'ME', 'Y', 'QE', 'BME', 'BY', 'BQ', and 'W'
frequency offsets except for 'ME', 'YE', 'QE', 'BME', 'BY', 'BQ', and 'W'
which all have a default of 'right'.

This might unintendedly lead to looking ahead, where the value for a later
27 changes: 6 additions & 21 deletions doc/source/whatsnew/v2.2.0.rst
Original file line number Diff line number Diff line change
@@ -232,29 +232,14 @@ Other API changes
Deprecations
~~~~~~~~~~~~

Deprecate aliases ``M`` and ``Q`` in favour of ``ME`` and ``QE`` for offsets
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Deprecate aliases ``M``, ``Q``, and ``Y`` in favour of ``ME``, ``QE``, and ``YE`` for offsets
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The alias ``M`` is deprecated in favour of ``ME`` for offsets, please use ``ME`` for "month end" instead of ``M`` (:issue:`9586`)
Deprecated the following frequency aliases (:issue:`9586`):

For example:

*Previous behavior*:

.. code-block:: ipython

In [7]: pd.date_range('2020-01-01', periods=3, freq='M')
Out [7]:
DatetimeIndex(['2020-01-31', '2020-02-29', '2020-03-31'],
dtype='datetime64[ns]', freq='M')

*Future behavior*:

.. ipython:: python

pd.date_range('2020-01-01', periods=3, freq='ME')

The alias ``Q`` is deprecated in favour of ``QE`` for offsets, please use ``QE`` for "quarter end" instead of ``Q`` (:issue:`9586`)
- ``M`` (month end) has been renamed ``ME`` for offsets
- ``Q`` (quarter end) has been renamed ``QE`` for offsets
- ``Y`` (year end) has been renamed ``YE`` for offsets

For example:

39 changes: 39 additions & 0 deletions pandas/_libs/tslibs/dtypes.pyx
Original file line number Diff line number Diff line change
@@ -214,6 +214,19 @@ OFFSET_TO_PERIOD_FREQSTR: dict = {
"QE-SEP": "Q-SEP",
"QE-OCT": "Q-OCT",
"QE-NOV": "Q-NOV",
"YE": "Y",
"YE-DEC": "Y-DEC",
"YE-JAN": "Y-JAN",
"YE-FEB": "Y-FEB",
"YE-MAR": "Y-MAR",
"YE-APR": "Y-APR",
"YE-MAY": "Y-MAY",
"YE-JUN": "Y-JUN",
"YE-JUL": "Y-JUL",
"YE-AUG": "Y-AUG",
"YE-SEP": "Y-SEP",
"YE-OCT": "Y-OCT",
"YE-NOV": "Y-NOV",
"W": "W",
"ME": "M",
"Y": "Y",
@@ -236,6 +249,32 @@ OFFSET_DEPR_FREQSTR: dict[str, str]= {
"Q-SEP": "QE-SEP",
"Q-OCT": "QE-OCT",
"Q-NOV": "QE-NOV",
"Y": "YE",
"Y-DEC": "YE-DEC",
"Y-JAN": "YE-JAN",
"Y-FEB": "YE-FEB",
"Y-MAR": "YE-MAR",
"Y-APR": "YE-APR",
"Y-MAY": "YE-MAY",
"Y-JUN": "YE-JUN",
"Y-JUL": "YE-JUL",
"Y-AUG": "YE-AUG",
"Y-SEP": "YE-SEP",
"Y-OCT": "YE-OCT",
"Y-NOV": "YE-NOV",
"A": "YE",
"A-DEC": "YE-DEC",
"A-JAN": "YE-JAN",
"A-FEB": "YE-FEB",
"A-MAR": "YE-MAR",
"A-APR": "YE-APR",
"A-MAY": "YE-MAY",
"A-JUN": "YE-JUN",
"A-JUL": "YE-JUL",
"A-AUG": "YE-AUG",
"A-SEP": "YE-SEP",
"A-OCT": "YE-OCT",
"A-NOV": "YE-NOV",
}
cdef dict c_OFFSET_TO_PERIOD_FREQSTR = OFFSET_TO_PERIOD_FREQSTR
cdef dict c_OFFSET_DEPR_FREQSTR = OFFSET_DEPR_FREQSTR
15 changes: 12 additions & 3 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
@@ -2518,7 +2518,7 @@ cdef class YearEnd(YearOffset):
"""

_default_month = 12
_prefix = "Y"
_prefix = "YE"
_day_opt = "end"

cdef readonly:
@@ -4562,7 +4562,7 @@ prefix_mapping = {
offset._prefix: offset
for offset in [
YearBegin, # 'YS'
YearEnd, # 'Y'
YearEnd, # 'YE'
BYearBegin, # 'BYS'
BYearEnd, # 'BY'
BusinessDay, # 'B'
@@ -4604,7 +4604,7 @@ _lite_rule_alias = {
"W": "W-SUN",
"QE": "QE-DEC",

"Y": "Y-DEC", # YearEnd(month=12),
"YE": "YE-DEC", # YearEnd(month=12),
"YS": "YS-JAN", # YearBegin(month=1),
"BY": "BY-DEC", # BYearEnd(month=12),
"BYS": "BYS-JAN", # BYearBegin(month=1),
@@ -4637,6 +4637,7 @@ _dont_uppercase = {
"qe-sep",
"qe-oct",
"qe-nov",
"ye",
}


@@ -4762,6 +4763,14 @@ cpdef to_offset(freq, bint is_period=False):
f"instead of \'{name}\'"
)
elif is_period is True and name in c_OFFSET_DEPR_FREQSTR:
if name.startswith("A"):
warnings.warn(
f"\'{name}\' is deprecated and will be removed in a future "
f"version, please use \'{c_DEPR_ABBREVS.get(name)}\' "
f"instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
name = c_OFFSET_DEPR_FREQSTR.get(name)

if sep != "" and not sep.isspace():
6 changes: 3 additions & 3 deletions pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
@@ -1520,7 +1520,7 @@ def isocalendar(self) -> DataFrame:
Examples
--------
>>> datetime_series = pd.Series(
... pd.date_range("2000-01-01", periods=3, freq="Y")
... pd.date_range("2000-01-01", periods=3, freq="YE")
... )
>>> datetime_series
0 2000-12-31
@@ -2058,10 +2058,10 @@ def isocalendar(self) -> DataFrame:
This method is available on Series with datetime values under
the ``.dt`` accessor, and directly on DatetimeIndex.

>>> idx = pd.date_range("2012-01-01", "2015-01-01", freq="Y")
>>> idx = pd.date_range("2012-01-01", "2015-01-01", freq="YE")
>>> idx
DatetimeIndex(['2012-12-31', '2013-12-31', '2014-12-31'],
dtype='datetime64[ns]', freq='Y-DEC')
dtype='datetime64[ns]', freq='YE-DEC')
>>> idx.is_leap_year
array([ True, False, False])

4 changes: 2 additions & 2 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
@@ -9199,11 +9199,11 @@ def resample(
Use frame.T.resample(...) instead.
closed : {{'right', 'left'}}, default None
Which side of bin interval is closed. The default is 'left'
for all frequency offsets except for 'ME', 'Y', 'Q', 'BME',
for all frequency offsets except for 'ME', 'YE', 'QE', 'BME',
'BA', 'BQ', and 'W' which all have a default of 'right'.
label : {{'right', 'left'}}, default None
Which bin edge label to label bucket with. The default is 'left'
for all frequency offsets except for 'ME', 'Y', 'Q', 'BME',
for all frequency offsets except for 'ME', 'YE', 'QE', 'BME',
'BA', 'BQ', and 'W' which all have a default of 'right'.
convention : {{'start', 'end', 's', 'e'}}, default 'start'
For `PeriodIndex` only, controls whether to use the start or
4 changes: 2 additions & 2 deletions pandas/core/resample.py
Original file line number Diff line number Diff line change
@@ -2130,7 +2130,7 @@ def __init__(
else:
freq = to_offset(freq)

end_types = {"ME", "Y", "QE", "BME", "BY", "BQ", "W"}
end_types = {"ME", "YE", "QE", "BME", "BY", "BQ", "W"}
rule = freq.rule_code
if rule in end_types or ("-" in rule and rule[: rule.find("-")] in end_types):
if closed is None:
@@ -2330,7 +2330,7 @@ def _adjust_bin_edges(
"BQ",
"BY",
"QE",
"Y",
"YE",
"W",
):
# If the right end-point is on the last day of the month, roll forwards
2 changes: 1 addition & 1 deletion pandas/core/series.py
Original file line number Diff line number Diff line change
@@ -5785,7 +5785,7 @@ def to_timestamp(
2023-01-31 1
2024-01-31 2
2025-01-31 3
Freq: Y-JAN, dtype: int64
Freq: YE-JAN, dtype: int64
"""
if not isinstance(self.index, PeriodIndex):
raise TypeError(f"unsupported Type {type(self.index).__name__}")
2 changes: 1 addition & 1 deletion pandas/tests/arithmetic/test_datetime64.py
Original file line number Diff line number Diff line change
@@ -1606,7 +1606,7 @@ def test_dt64_series_arith_overflow(self):
# GH#12534, fixed by GH#19024
dt = Timestamp("1700-01-31")
td = Timedelta("20000 Days")
dti = date_range("1949-09-30", freq="100Y", periods=4)
dti = date_range("1949-09-30", freq="100YE", periods=4)
ser = Series(dti)
msg = "Overflow in int64 addition"
with pytest.raises(OverflowError, match=msg):
2 changes: 1 addition & 1 deletion pandas/tests/arrays/period/test_arrow_compat.py
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ def test_arrow_extension_type():
"data, freq",
[
(pd.date_range("2017", periods=3), "D"),
(pd.date_range("2017", periods=3, freq="Y"), "Y-DEC"),
(pd.date_range("2017", periods=3, freq="YE"), "Y-DEC"),
],
)
def test_arrow_array(data, freq):
2 changes: 1 addition & 1 deletion pandas/tests/arrays/test_datetimelike.py
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@


# TODO: more freq variants
@pytest.fixture(params=["D", "B", "W", "ME", "QE", "Y"])
@pytest.fixture(params=["D", "B", "W", "ME", "QE", "YE"])
def freqstr(request):
"""Fixture returning parametrized frequency in string format."""
return request.param
8 changes: 6 additions & 2 deletions pandas/tests/arrays/test_datetimes.py
Original file line number Diff line number Diff line change
@@ -748,10 +748,14 @@ def test_iter_zoneinfo_fold(self, tz):
("2ME", "2M"),
("2QE", "2Q"),
("2QE-SEP", "2Q-SEP"),
("1YE", "1Y"),
("2YE-MAR", "2Y-MAR"),
("1YE", "1A"),
("2YE-MAR", "2A-MAR"),
],
)
def test_date_range_frequency_M_Q_deprecated(self, freq, freq_depr):
# GH#9586
def test_date_range_frequency_M_Q_Y_A_deprecated(self, freq, freq_depr):
# GH#9586, GH#54275
depr_msg = (
f"'{freq_depr[1:]}' will be deprecated, please use '{freq[1:]}' instead."
)
6 changes: 5 additions & 1 deletion pandas/tests/frame/methods/test_asfreq.py
Original file line number Diff line number Diff line change
@@ -240,9 +240,13 @@ def test_asfreq_2ME(self, freq, freq_half):
("2ME", "2M"),
("2QE", "2Q"),
("2QE-SEP", "2Q-SEP"),
("1YE", "1Y"),
("2YE-MAR", "2Y-MAR"),
("1YE", "1A"),
("2YE-MAR", "2A-MAR"),
],
)
def test_asfreq_frequency_M_Q_deprecated(self, freq, freq_depr):
def test_asfreq_frequency_M_Q_Y_A_deprecated(self, freq, freq_depr):
# GH#9586
depr_msg = (
f"'{freq_depr[1:]}' will be deprecated, please use '{freq[1:]}' instead."
2 changes: 1 addition & 1 deletion pandas/tests/frame/methods/test_reindex.py
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ def test_dti_set_index_reindex_datetimeindex(self):
# GH#6631
df = DataFrame(np.random.default_rng(2).random(6))
idx1 = date_range("2011/01/01", periods=6, freq="ME", tz="US/Eastern")
idx2 = date_range("2013", periods=6, freq="Y", tz="Asia/Tokyo")
idx2 = date_range("2013", periods=6, freq="YE", tz="Asia/Tokyo")

df = df.set_index(idx1)
tm.assert_index_equal(df.index, idx1)
6 changes: 3 additions & 3 deletions pandas/tests/frame/methods/test_to_timestamp.py
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
import pandas._testing as tm


def _get_with_delta(delta, freq="Y-DEC"):
def _get_with_delta(delta, freq="YE-DEC"):
return date_range(
to_datetime("1/1/2001") + delta,
to_datetime("12/31/2009") + delta,
@@ -36,7 +36,7 @@ def test_to_timestamp(self, frame_or_series):
obj["mix"] = "a"
obj = tm.get_obj(obj, frame_or_series)

exp_index = date_range("1/1/2001", end="12/31/2009", freq="Y-DEC")
exp_index = date_range("1/1/2001", end="12/31/2009", freq="YE-DEC")
exp_index = exp_index + Timedelta(1, "D") - Timedelta(1, "ns")
result = obj.to_timestamp("D", "end")
tm.assert_index_equal(result.index, exp_index)
@@ -82,7 +82,7 @@ def test_to_timestamp_columns(self):
# columns
df = df.T

exp_index = date_range("1/1/2001", end="12/31/2009", freq="Y-DEC")
exp_index = date_range("1/1/2001", end="12/31/2009", freq="YE-DEC")
exp_index = exp_index + Timedelta(1, "D") - Timedelta(1, "ns")
result = df.to_timestamp("D", "end", axis=1)
tm.assert_index_equal(result.columns, exp_index)
2 changes: 1 addition & 1 deletion pandas/tests/frame/test_repr.py
Original file line number Diff line number Diff line change
@@ -357,7 +357,7 @@ def test_repr_np_nat_with_object(self, arg, box, expected):
assert result == expected

def test_frame_datetime64_pre1900_repr(self):
df = DataFrame({"year": date_range("1/1/1700", periods=50, freq="Y-DEC")})
df = DataFrame({"year": date_range("1/1/1700", periods=50, freq="YE-DEC")})
# it works!
repr(df)

6 changes: 3 additions & 3 deletions pandas/tests/groupby/test_timegrouper.py
Original file line number Diff line number Diff line change
@@ -192,7 +192,7 @@ def test_timegrouper_with_reg_groups(self):
).set_index(["Date", "Buyer"])

msg = "The default value of numeric_only"
result = df.groupby([Grouper(freq="Y"), "Buyer"]).sum(numeric_only=True)
result = df.groupby([Grouper(freq="YE"), "Buyer"]).sum(numeric_only=True)
tm.assert_frame_equal(result, expected)

expected = DataFrame(
@@ -335,7 +335,7 @@ def test_timegrouper_with_reg_groups(self):
)
tm.assert_frame_equal(result, expected)

@pytest.mark.parametrize("freq", ["D", "ME", "Y", "QE-APR"])
@pytest.mark.parametrize("freq", ["D", "ME", "YE", "QE-APR"])
def test_timegrouper_with_reg_groups_freq(self, freq):
# GH 6764 multiple grouping with/without sort
df = DataFrame(
@@ -906,7 +906,7 @@ def test_groupby_apply_timegrouper_with_nat_apply_squeeze(

# We need to create a GroupBy object with only one non-NaT group,
# so use a huge freq so that all non-NaT dates will be grouped together
tdg = Grouper(key="Date", freq="100Y")
tdg = Grouper(key="Date", freq="100YE")
gb = df.groupby(tdg)

# check that we will go through the singular_series path
Loading