diff --git a/doc/source/whatsnew/v0.25.1.rst b/doc/source/whatsnew/v0.25.1.rst index c80195af413f7..a4e792091cb4b 100644 --- a/doc/source/whatsnew/v0.25.1.rst +++ b/doc/source/whatsnew/v0.25.1.rst @@ -152,7 +152,7 @@ ExtensionArray Other ^^^^^ - +- Bug in :meth:`Series.replace` and :meth:`DataFrame.replace` when replacing timezone-aware timestamps using a dict-like replacer (:issue:`27720`) - - - diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 821c35e0cce2f..2b783e3e7aaf8 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -6658,9 +6658,8 @@ def replace( else: # need a non-zero len on all axes - for a in self._AXIS_ORDERS: - if not len(self._get_axis(a)): - return self + if not self.size: + return self new_data = self._data if is_dict_like(to_replace): diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index 8956821740bf3..b2019e3e59dda 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -7,7 +7,7 @@ import numpy as np -from pandas._libs import internals as libinternals, lib +from pandas._libs import Timedelta, Timestamp, internals as libinternals, lib from pandas.util._validators import validate_bool_kwarg from pandas.core.dtypes.cast import ( @@ -602,9 +602,10 @@ def comp(s, regex=False): """ if isna(s): return isna(values) - if hasattr(s, "asm8"): + if isinstance(s, (Timedelta, Timestamp)) and getattr(s, "tz", None) is None: + return _compare_or_regex_search( - maybe_convert_objects(values), getattr(s, "asm8"), regex + maybe_convert_objects(values), s.asm8, regex ) return _compare_or_regex_search(values, s, regex) diff --git a/pandas/tests/indexing/test_coercion.py b/pandas/tests/indexing/test_coercion.py index dea1d5114f1b9..ed80e249220fd 100644 --- a/pandas/tests/indexing/test_coercion.py +++ b/pandas/tests/indexing/test_coercion.py @@ -1029,22 +1029,20 @@ def test_replace_series(self, how, to_key, from_key): tm.assert_series_equal(result, exp) - # TODO(jbrockmendel) commented out to only have a single xfail printed - @pytest.mark.xfail( - reason="GH #18376, tzawareness-compat bug in BlockManager.replace_list" + @pytest.mark.parametrize("how", ["dict", "series"]) + @pytest.mark.parametrize( + "to_key", + ["timedelta64[ns]", "bool", "object", "complex128", "float64", "int64"], ) - # @pytest.mark.parametrize('how', ['dict', 'series']) - # @pytest.mark.parametrize('to_key', ['timedelta64[ns]', 'bool', 'object', - # 'complex128', 'float64', 'int64']) - # @pytest.mark.parametrize('from_key', ['datetime64[ns, UTC]', - # 'datetime64[ns, US/Eastern]']) - # def test_replace_series_datetime_tz(self, how, to_key, from_key): - def test_replace_series_datetime_tz(self): + @pytest.mark.parametrize( + "from_key", ["datetime64[ns, UTC]", "datetime64[ns, US/Eastern]"] + ) + def test_replace_series_datetime_tz(self, how, to_key, from_key): how = "series" from_key = "datetime64[ns, US/Eastern]" to_key = "timedelta64[ns]" - index = pd.Index([3, 4], name="xxx") + index = pd.Index([3, 4], name="xyz") obj = pd.Series(self.rep[from_key], index=index, name="yyy") assert obj.dtype == from_key @@ -1061,24 +1059,17 @@ def test_replace_series_datetime_tz(self): tm.assert_series_equal(result, exp) - # TODO(jreback) commented out to only have a single xfail printed - @pytest.mark.xfail( - reason="different tz, currently mask_missing raises SystemError", strict=False + @pytest.mark.parametrize("how", ["dict", "series"]) + @pytest.mark.parametrize( + "to_key", + ["datetime64[ns]", "datetime64[ns, UTC]", "datetime64[ns, US/Eastern]"], ) - # @pytest.mark.parametrize('how', ['dict', 'series']) - # @pytest.mark.parametrize('to_key', [ - # 'datetime64[ns]', 'datetime64[ns, UTC]', - # 'datetime64[ns, US/Eastern]']) - # @pytest.mark.parametrize('from_key', [ - # 'datetime64[ns]', 'datetime64[ns, UTC]', - # 'datetime64[ns, US/Eastern]']) - # def test_replace_series_datetime_datetime(self, how, to_key, from_key): - def test_replace_series_datetime_datetime(self): - how = "dict" - to_key = "datetime64[ns]" - from_key = "datetime64[ns]" - - index = pd.Index([3, 4], name="xxx") + @pytest.mark.parametrize( + "from_key", + ["datetime64[ns]", "datetime64[ns, UTC]", "datetime64[ns, US/Eastern]"], + ) + def test_replace_series_datetime_datetime(self, how, to_key, from_key): + index = pd.Index([3, 4], name="xyz") obj = pd.Series(self.rep[from_key], index=index, name="yyy") assert obj.dtype == from_key