diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 834477f2aa46a..54e328170de1e 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -732,6 +732,7 @@ Timedelta Timezones ^^^^^^^^^ - Bug in :meth:`DatetimeIndex.union`, :meth:`DatetimeIndex.intersection`, and :meth:`DatetimeIndex.symmetric_difference` changing timezone to UTC when merging two DatetimeIndex objects with the same timezone but different units (:issue:`60080`) +- Bug in :meth:`Series.dt.tz_localize` with a timezone-aware :class:`ArrowDtype` incorrectly converting to UTC when ``tz=None`` (:issue:`61780`) - Numeric diff --git a/pandas/core/arrays/arrow/array.py b/pandas/core/arrays/arrow/array.py index 60dc7ea2a1e96..07c8ab6d4f2cb 100644 --- a/pandas/core/arrays/arrow/array.py +++ b/pandas/core/arrays/arrow/array.py @@ -2953,7 +2953,7 @@ def _dt_tz_localize( if nonexistent_pa is None: raise NotImplementedError(f"{nonexistent=} is not supported") if tz is None: - result = self._pa_array.cast(pa.timestamp(self.dtype.pyarrow_dtype.unit)) + result = pc.local_timestamp(self._pa_array) else: result = pc.assume_timezone( self._pa_array, str(tz), ambiguous=ambiguous, nonexistent=nonexistent_pa diff --git a/pandas/tests/extension/test_arrow.py b/pandas/tests/extension/test_arrow.py index 8ab88690c77e7..66f3264401668 100644 --- a/pandas/tests/extension/test_arrow.py +++ b/pandas/tests/extension/test_arrow.py @@ -2679,8 +2679,9 @@ def test_dt_tz_localize_unsupported_tz_options(): ser.dt.tz_localize("UTC", nonexistent="NaT") -@pytest.mark.xfail(reason="Converts to UTC before localizing GH#61780") -def test_dt_tz_localize_none(): +def test_dt_tz_localize_none(request): + _require_timezone_database(request) + ser = pd.Series( [datetime(year=2023, month=1, day=2, hour=3), None], dtype=ArrowDtype(pa.timestamp("ns", tz="US/Pacific")),