diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index f2ec08c61a6d8..5621476d3d4e7 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -544,6 +544,7 @@ Other API Changes - :class:`Index` subtraction will attempt to operate element-wise instead of raising ``TypeError`` (:issue:`19369`) - :class:`pandas.io.formats.style.Styler` supports a ``number-format`` property when using :meth:`~pandas.io.formats.style.Styler.to_excel` (:issue:`22015`) - :meth:`DataFrame.corr` and :meth:`Series.corr` now raise a ``ValueError`` along with a helpful error message instead of a ``KeyError`` when supplied with an invalid method (:issue:`22298`) +- :meth:`shift` will now always return a copy, instead of the previous behaviour of returning self when shifting by 0 (:issue:`22397`) .. _whatsnew_0240.deprecations: diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index eb8821382037d..12e1dd1052e0b 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -548,7 +548,7 @@ def shift(self, n, freq=None): if n == 0: # immutable so OK - return self + return self.copy() if self.freq is None: raise NullFrequencyError("Cannot shift with no freq") diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 2e5da21f573b0..cdc5b4310bce2 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -8282,7 +8282,7 @@ def mask(self, cond, other=np.nan, inplace=False, axis=None, level=None, @Appender(_shared_docs['shift'] % _shared_doc_kwargs) def shift(self, periods=1, freq=None, axis=0): if periods == 0: - return self + return self.copy() block_axis = self._get_block_manager_axis(axis) if freq is None: diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index 3393d7704e411..f0c6c969f765a 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -227,3 +227,22 @@ def test_valid_deprecated(self): # GH18800 with tm.assert_produces_warning(FutureWarning): pd.Series([]).valid() + + @pytest.mark.parametrize("s", [ + Series([np.arange(5)]), + pd.date_range('1/1/2011', periods=24, freq='H'), + pd.Series(range(5), index=pd.date_range("2017", periods=5)) + ]) + @pytest.mark.parametrize("shift_size", [0, 1, 2]) + def test_shift_always_copy(self, s, shift_size): + # GH22397 + assert s.shift(shift_size) is not s + + @pytest.mark.parametrize("move_by_freq", [ + pd.Timedelta('1D'), + pd.Timedelta('1M'), + ]) + def test_datetime_shift_always_copy(self, move_by_freq): + # GH22397 + s = pd.Series(range(5), index=pd.date_range("2017", periods=5)) + assert s.shift(freq=move_by_freq) is not s