diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 2f70d4e5946a0..135e97f309d7e 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -562,6 +562,7 @@ Deprecations - :meth:`Series.str.cat` has deprecated using arbitrary list-likes *within* list-likes. A list-like container may still contain many ``Series``, ``Index`` or 1-dimensional ``np.ndarray``, or alternatively, only scalar values. (:issue:`21950`) - :meth:`FrozenNDArray.searchsorted` has deprecated the ``v`` parameter in favor of ``value`` (:issue:`14645`) +- :func:`DatetimeIndex.shift` now accepts ``periods`` argument instead of ``n`` for consistency with :func:`Index.shift` and :func:`Series.shift`. Using ``n`` throws a deprecation warning (:issue:`22458`) .. _whatsnew_0240.prior_deprecations: diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 69925ce1c520e..91c119808db52 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -38,6 +38,7 @@ from pandas.core.algorithms import checked_add_with_arr from .base import ExtensionOpsMixin +from pandas.util._decorators import deprecate_kwarg def _make_comparison_op(op, cls): @@ -522,40 +523,54 @@ def _addsub_offset_array(self, other, op): kwargs['freq'] = 'infer' return type(self)(res_values, **kwargs) - def shift(self, n, freq=None): + @deprecate_kwarg(old_arg_name='n', new_arg_name='periods') + def shift(self, periods, freq=None): """ - Specialized shift which produces a Datetime/Timedelta Array/Index + Shift index by desired number of time frequency increments. + + This method is for shifting the values of datetime-like indexes + by a specified time increment a given number of times. Parameters ---------- - n : int - Periods to shift by - freq : DateOffset or timedelta-like, optional + periods : int + Number of periods (or increments) to shift by, + can be positive or negative. + + .. versionchanged:: 0.24.0 + + freq : pandas.DateOffset, pandas.Timedelta or string, optional + Frequency increment to shift by. + If None, the index is shifted by its own `freq` attribute. + Offset aliases are valid strings, e.g., 'D', 'W', 'M' etc. Returns ------- - shifted : same type as self + pandas.DatetimeIndex + Shifted index. + + See Also + -------- + Index.shift : Shift values of Index. """ if freq is not None and freq != self.freq: if isinstance(freq, compat.string_types): freq = frequencies.to_offset(freq) - offset = n * freq + offset = periods * freq result = self + offset - if hasattr(self, 'tz'): result._tz = self.tz - return result - if n == 0: + if periods == 0: # immutable so OK return self.copy() if self.freq is None: raise NullFrequencyError("Cannot shift with no freq") - start = self[0] + n * self.freq - end = self[-1] + n * self.freq + start = self[0] + periods * self.freq + end = self[-1] + periods * self.freq attribs = self._get_attributes_dict() return self._generate_range(start=start, end=end, periods=None, **attribs) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 75baeab402734..b72d8cbf02bc6 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -8288,6 +8288,11 @@ def mask(self, cond, other=np.nan, inplace=False, axis=None, level=None, See Notes. axis : %(axes_single_arg)s + See Also + -------- + Index.shift : Shift values of Index. + DatetimeIndex.shift : Shift values of DatetimeIndex. + Notes ----- If freq is specified then the index values are shifted but the data diff --git a/pandas/tests/indexes/datetimes/test_ops.py b/pandas/tests/indexes/datetimes/test_ops.py index 24d99abaf44a8..b60b222d095b9 100644 --- a/pandas/tests/indexes/datetimes/test_ops.py +++ b/pandas/tests/indexes/datetimes/test_ops.py @@ -540,6 +540,16 @@ def test_shift(self): shifted = rng.shift(1, freq=CDay()) assert shifted[0] == rng[0] + CDay() + def test_shift_periods(self): + # GH #22458 : argument 'n' was deprecated in favor of 'periods' + idx = pd.DatetimeIndex(start=START, end=END, + periods=3) + tm.assert_index_equal(idx.shift(periods=0), idx) + tm.assert_index_equal(idx.shift(0), idx) + with tm.assert_produces_warning(FutureWarning, + check_stacklevel=True): + tm.assert_index_equal(idx.shift(n=0), idx) + def test_pickle_unpickle(self): unpickled = tm.round_trip_pickle(self.rng) assert unpickled.freq is not None