diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 120976d475ac51..7fe7970199b5ed 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -539,6 +539,7 @@ or ``matplotlib.Axes.plot``. See :ref:`plotting.formatters` for more. - Changed the the default value of `inplace` in :meth:`DataFrame.set_index` and :meth:`Series.set_axis`. It now defaults to ``False`` (:issue:`27600`) - Removed the previously deprecated :attr:`Series.cat.categorical`, :attr:`Series.cat.index`, :attr:`Series.cat.name` (:issue:`24751`) - :func:`to_datetime` no longer accepts "box" argument, always returns :class:`DatetimeIndex` or :class:`Index`, :class:`Series`, or :class:`DataFrame` (:issue:`24486`) +- :func:`to_timedelta`, :class:`Timedelta`, and :class:`TimedeltaIndex` no longer allow "M", "y", or "Y" for the "unit" argument (:issue:`23264`) - Removed the previously deprecated ``time_rule`` keyword from (non-public) :func:`offsets.generate_range`, which has been moved to :func:`core.arrays._ranges.generate_range` (:issue:`24157`) - :meth:`DataFrame.loc` or :meth:`Series.loc` with listlike indexers and missing labels will no longer reindex (:issue:`17295`) - :meth:`DataFrame.to_excel` and :meth:`Series.to_excel` with non-existent columns will no longer reindex (:issue:`17295`) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 726d664c1ebea3..ddff72beab0a70 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1,6 +1,5 @@ import collections import textwrap -import warnings import cython @@ -1204,9 +1203,10 @@ class Timedelta(_Timedelta): "milliseconds, microseconds, nanoseconds]") if unit in {'Y', 'y', 'M'}: - warnings.warn("M and Y units are deprecated and " - "will be removed in a future version.", - FutureWarning, stacklevel=1) + raise ValueError( + "Units 'M' and 'Y' are no longer supported, as they do not " + "represent unambiguous timedelta values durations." + ) if isinstance(value, Timedelta): value = value.value diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index 57cb170dc0ae88..dcbac3c2e19cff 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -1,6 +1,5 @@ """ implement the TimedeltaIndex """ from datetime import datetime -import warnings import numpy as np @@ -201,11 +200,9 @@ def __new__( ) if unit in {"Y", "y", "M"}: - warnings.warn( - "M and Y units are deprecated and " - "will be removed in a future version.", - FutureWarning, - stacklevel=2, + raise ValueError( + "Units 'M' and 'Y' are no longer supported, as they do not " + "represent unambiguous timedelta values durations." ) if isinstance(data, TimedeltaArray): diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index cc31317980ca8d..c624ddb2eb4d1e 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -2,8 +2,6 @@ timedelta support tools """ -import warnings - import numpy as np from pandas._libs.tslibs import NaT @@ -100,10 +98,9 @@ def to_timedelta(arg, unit="ns", box=True, errors="raise"): raise ValueError("errors must be one of 'ignore', 'raise', or 'coerce'}") if unit in {"Y", "y", "M"}: - warnings.warn( - "M and Y units are deprecated and will be removed in a future version.", - FutureWarning, - stacklevel=2, + raise ValueError( + "Units 'M' and 'Y' are no longer supported, as they do not " + "represent unambiguous timedelta values durations." ) if arg is None: diff --git a/pandas/tests/indexes/timedeltas/test_timedelta.py b/pandas/tests/indexes/timedeltas/test_timedelta.py index a62bd7f39e0392..35575f3349f833 100644 --- a/pandas/tests/indexes/timedeltas/test_timedelta.py +++ b/pandas/tests/indexes/timedeltas/test_timedelta.py @@ -1,5 +1,4 @@ from datetime import timedelta -import re import numpy as np import pytest @@ -326,11 +325,10 @@ def test_freq_conversion(self): tm.assert_index_equal(result, expected) @pytest.mark.parametrize("unit", ["Y", "y", "M"]) - def test_unit_m_y_deprecated(self, unit): - with tm.assert_produces_warning(FutureWarning) as w: + def test_unit_m_y_raises(self, unit): + msg = "Units 'M' and 'Y' are no longer supported" + with pytest.raises(ValueError, match=msg): TimedeltaIndex([1, 3, 7], unit) - msg = r".* units are deprecated .*" - assert re.match(msg, str(w[0].message)) class TestTimeSeries: diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index 5a5724401029c7..bd82be40ad3b28 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -1,6 +1,5 @@ """ test the scalar Timedelta """ from datetime import timedelta -import re import numpy as np import pytest @@ -318,12 +317,9 @@ def test_nat_converters(self): assert result.dtype.kind == "M" assert result.astype("int64") == iNaT - @pytest.mark.filterwarnings("ignore:M and Y units are deprecated") @pytest.mark.parametrize( "units, np_unit", [ - (["Y", "y"], "Y"), - (["M"], "M"), (["W", "w"], "W"), (["D", "d", "days", "day", "Days", "Day"], "D"), ( @@ -426,19 +422,16 @@ def test_unit_parser(self, units, np_unit, wrapper): assert result == expected @pytest.mark.parametrize("unit", ["Y", "y", "M"]) - def test_unit_m_y_deprecated(self, unit): - with tm.assert_produces_warning(FutureWarning) as w1: + def test_unit_m_y_raises(self, unit): + msg = "Units 'M' and 'Y' are no longer supported" + with pytest.raises(ValueError, match=msg): Timedelta(10, unit) - msg = r".* units are deprecated .*" - assert re.match(msg, str(w1[0].message)) - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False) as w2: + + with pytest.raises(ValueError, match=msg): to_timedelta(10, unit) - msg = r".* units are deprecated .*" - assert re.match(msg, str(w2[0].message)) - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False) as w3: + + with pytest.raises(ValueError, match=msg): to_timedelta([1, 2], unit) - msg = r".* units are deprecated .*" - assert re.match(msg, str(w3[0].message)) def test_numeric_conversions(self): assert Timedelta(0) == np.timedelta64(0, "ns")