Repository: pandas-dev/pandas

Issue:
BUG: resampling empty series loses time zone from dtype
### Pandas version checks

- [X] I have checked that this issue has not already been reported.

- [X] I have confirmed this bug exists on the [latest version](https://pandas.pydata.org/docs/whatsnew/index.html) of pandas.

- [ ] I have confirmed this bug exists on the [main branch](https://pandas.pydata.org/docs/dev/getting_started/install.html#installing-the-development-version-of-pandas) of pandas.


### Reproducible Example

```python
df = pd.DataFrame({
    'ts': [],
    'values': []
}).astype({'ts': 'datetime64[ns, Atlantic/Faroe]'})
df.resample('2MS', on='ts', closed='left', label='left', origin='start')['values'].sum().index
```


### Issue Description

this prints
```python
DatetimeIndex([], dtype='datetime64[ns]', name='ts', freq='2MS')
```

### Expected Behavior

```
DatetimeIndex([], dtype='datetime64[ns, Atlantic/Faroe]', name='ts', freq='2MS')
```

note that this works fine if the series isn't empty
```python
In [27]: df = pd.DataFrame({
    ...:     'ts': [datetime(2020, 1, 1)],
    ...:     'values': [10]
    ...: })
    ...: df['ts'] = df['ts'].dt.tz_localize('Atlantic/Faroe')
    ...: df.resample('2MS', on='ts', closed='left', label='left', origin='start')['values'].sum().index
Out[27]: DatetimeIndex(['2020-01-01 00:00:00+00:00'], dtype='datetime64[ns, Atlantic/Faroe]', name='ts', freq='2MS')
```

### Installed Versions

<details>

INSTALLED VERSIONS
------------------
commit           : 965ceca9fd796940050d6fc817707bba1c4f9bff
python           : 3.10.6.final.0
python-bits      : 64
OS               : Linux
OS-release       : 5.10.102.1-microsoft-standard-WSL2
Version          : #1 SMP Wed Mar 2 00:30:59 UTC 2022
machine          : x86_64
processor        : x86_64
byteorder        : little
LC_ALL           : None
LANG             : en_GB.UTF-8
LOCALE           : en_GB.UTF-8

pandas           : 2.0.2
numpy            : 1.24.3
pytz             : 2023.3
dateutil         : 2.8.2
setuptools       : 67.6.1
pip              : 23.0.1
Cython           : None
pytest           : 7.3.1
hypothesis       : None
sphinx           : None
blosc            : None
feather          : None
xlsxwriter       : None
lxml.etree       : None
html5lib         : None
pymysql          : None
psycopg2         : None
jinja2           : 3.1.2
IPython          : 8.13.2
pandas_datareader: None
bs4              : 4.12.2
bottleneck       : None
brotli           : None
fastparquet      : None
fsspec           : None
gcsfs            : None
matplotlib       : 3.7.1
numba            : None
numexpr          : None
odfpy            : None
openpyxl         : None
pandas_gbq       : None
pyarrow          : 12.0.0
pyreadstat       : None
pyxlsb           : None
s3fs             : None
scipy            : None
snappy           : None
sqlalchemy       : None
tables           : None
tabulate         : None
xarray           : None
xlrd             : None
zstandard        : None
tzdata           : 2023.3
qtpy             : None
pyqt5            : None

</details>



Discussion:

Patch:
diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst
index d9cdc8beaebea..35566f8b63a19 100644
--- a/doc/source/whatsnew/v2.1.0.rst
+++ b/doc/source/whatsnew/v2.1.0.rst
@@ -457,6 +457,7 @@ Plotting
 Groupby/resample/rolling
 ^^^^^^^^^^^^^^^^^^^^^^^^
 - Bug in :meth:`DataFrame.resample` and :meth:`Series.resample` in incorrectly allowing non-fixed ``freq`` when resampling on a :class:`TimedeltaIndex` (:issue:`51896`)
+- Bug in :meth:`DataFrame.resample` and :meth:`Series.resample` losing time zone when resampling empty data (:issue:`53664`)
 - Bug in :meth:`DataFrameGroupBy.idxmin`, :meth:`SeriesGroupBy.idxmin`, :meth:`DataFrameGroupBy.idxmax`, :meth:`SeriesGroupBy.idxmax` return wrong dtype when used on empty DataFrameGroupBy or SeriesGroupBy (:issue:`51423`)
 - Bug in weighted rolling aggregations when specifying ``min_periods=0`` (:issue:`51449`)
 - Bug in :meth:`DataFrame.groupby` and :meth:`Series.groupby`, where, when the index of the
diff --git a/pandas/core/resample.py b/pandas/core/resample.py
index a9faad4cbef6a..3fc0c47dd175e 100644
--- a/pandas/core/resample.py
+++ b/pandas/core/resample.py
@@ -1892,7 +1892,9 @@ def _get_time_bins(self, ax: DatetimeIndex):
             )
 
         if len(ax) == 0:
-            binner = labels = DatetimeIndex(data=[], freq=self.freq, name=ax.name)
+            binner = labels = DatetimeIndex(
+                data=[], freq=self.freq, name=ax.name, dtype=ax.dtype
+            )
             return binner, [], labels
 
         first, last = _get_timestamp_range_edges(
@@ -2023,8 +2025,10 @@ def _get_time_period_bins(self, ax: DatetimeIndex):
 
         freq = self.freq
 
-        if not len(ax):
-            binner = labels = PeriodIndex(data=[], freq=freq, name=ax.name)
+        if len(ax) == 0:
+            binner = labels = PeriodIndex(
+                data=[], freq=freq, name=ax.name, dtype=ax.dtype
+            )
             return binner, [], labels
 
         labels = binner = period_range(start=ax[0], end=ax[-1], freq=freq, name=ax.name)


Test patch:
diff --git a/pandas/tests/resample/test_datetime_index.py b/pandas/tests/resample/test_datetime_index.py
index 389db2d36474d..0f52f2d1c65ee 100644
--- a/pandas/tests/resample/test_datetime_index.py
+++ b/pandas/tests/resample/test_datetime_index.py
@@ -1968,3 +1968,19 @@ def test_long_rule_non_nano():
     )
     expected = Series([1.0, 3.0, 6.5, 4.0, 3.0, 6.5, 4.0, 3.0, 6.5], index=expected_idx)
     tm.assert_series_equal(result, expected)
+
+
+def test_resample_empty_series_with_tz():
+    # GH#53664
+    df = DataFrame({"ts": [], "values": []}).astype(
+        {"ts": "datetime64[ns, Atlantic/Faroe]"}
+    )
+    result = df.resample("2MS", on="ts", closed="left", label="left", origin="start")[
+        "values"
+    ].sum()
+
+    expected_idx = DatetimeIndex(
+        [], freq="2MS", name="ts", dtype="datetime64[ns, Atlantic/Faroe]"
+    )
+    expected = Series([], index=expected_idx, name="values", dtype="float64")
+    tm.assert_series_equal(result, expected)