Skip to content

Commit 99d7fad

Browse files
authored
BUG: preserve timezone info when writing empty tz-aware series to HDF5 (#37072)
1 parent 15988be commit 99d7fad

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ I/O
484484
- Bug in :meth:`DataFrame.to_html`, :meth:`DataFrame.to_string`, and :meth:`DataFrame.to_latex` ignoring the ``na_rep`` argument when ``float_format`` was also specified (:issue:`9046`, :issue:`13828`)
485485
- Bug in output rendering of complex numbers showing too many trailing zeros (:issue:`36799`)
486486
- Bug in :class:`HDFStore` threw a ``TypeError`` when exporting an empty :class:`DataFrame` with ``datetime64[ns, tz]`` dtypes with a fixed HDF5 store (:issue:`20594`)
487+
- Bug in :class:`HDFStore` was dropping timezone information when exporting :class:`Series` with ``datetime64[ns, tz]`` dtypes with a fixed HDF5 store (:issue:`20594`)
487488

488489
Plotting
489490
^^^^^^^^

pandas/io/pytables.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
is_string_dtype,
4646
is_timedelta64_dtype,
4747
)
48-
from pandas.core.dtypes.generic import ABCExtensionArray
4948
from pandas.core.dtypes.missing import array_equivalent
5049

5150
from pandas import (
@@ -63,6 +62,7 @@
6362
from pandas.core.arrays import Categorical, DatetimeArray, PeriodArray
6463
import pandas.core.common as com
6564
from pandas.core.computation.pytables import PyTablesExpr, maybe_expression
65+
from pandas.core.construction import extract_array
6666
from pandas.core.indexes.api import ensure_index
6767

6868
from pandas.io.common import stringify_path
@@ -2968,11 +2968,12 @@ def write_array_empty(self, key: str, value: ArrayLike):
29682968
node._v_attrs.value_type = str(value.dtype)
29692969
node._v_attrs.shape = value.shape
29702970

2971-
def write_array(self, key: str, value: ArrayLike, items: Optional[Index] = None):
2972-
# TODO: we only have one test that gets here, the only EA
2971+
def write_array(self, key: str, obj: FrameOrSeries, items: Optional[Index] = None):
2972+
# TODO: we only have a few tests that get here, the only EA
29732973
# that gets passed is DatetimeArray, and we never have
29742974
# both self._filters and EA
2975-
assert isinstance(value, (np.ndarray, ABCExtensionArray)), type(value)
2975+
2976+
value = extract_array(obj, extract_numpy=True)
29762977

29772978
if key in self.group:
29782979
self._handle.remove_node(self.group, key)
@@ -3077,7 +3078,7 @@ def read(
30773078
def write(self, obj, **kwargs):
30783079
super().write(obj, **kwargs)
30793080
self.write_index("index", obj.index)
3080-
self.write_array("values", obj.values)
3081+
self.write_array("values", obj)
30813082
self.attrs.name = obj.name
30823083

30833084

pandas/tests/io/pytables/test_timezones.py

+29-2
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,11 @@ def test_timezones_fixed_format_frame_non_empty(setup_path):
296296
tm.assert_frame_equal(result, df)
297297

298298

299-
@pytest.mark.parametrize("dtype", ["datetime64[ns, UTC]", "datetime64[ns, US/Eastern]"])
300-
def test_timezones_fixed_format_frame_empty(setup_path, dtype):
299+
def test_timezones_fixed_format_frame_empty(setup_path, tz_aware_fixture):
300+
# GH 20594
301+
302+
dtype = pd.DatetimeTZDtype(tz=tz_aware_fixture)
303+
301304
with ensure_clean_store(setup_path) as store:
302305
s = Series(dtype=dtype)
303306
df = DataFrame({"A": s})
@@ -306,6 +309,30 @@ def test_timezones_fixed_format_frame_empty(setup_path, dtype):
306309
tm.assert_frame_equal(result, df)
307310

308311

312+
def test_timezones_fixed_format_series_nonempty(setup_path, tz_aware_fixture):
313+
# GH 20594
314+
315+
dtype = pd.DatetimeTZDtype(tz=tz_aware_fixture)
316+
317+
with ensure_clean_store(setup_path) as store:
318+
s = Series([0], dtype=dtype)
319+
store["s"] = s
320+
result = store["s"]
321+
tm.assert_series_equal(result, s)
322+
323+
324+
def test_timezones_fixed_format_series_empty(setup_path, tz_aware_fixture):
325+
# GH 20594
326+
327+
dtype = pd.DatetimeTZDtype(tz=tz_aware_fixture)
328+
329+
with ensure_clean_store(setup_path) as store:
330+
s = Series(dtype=dtype)
331+
store["s"] = s
332+
result = store["s"]
333+
tm.assert_series_equal(result, s)
334+
335+
309336
def test_fixed_offset_tz(setup_path):
310337
rng = date_range("1/1/2000 00:00:00-07:00", "1/30/2000 00:00:00-07:00")
311338
frame = DataFrame(np.random.randn(len(rng), 4), index=rng)

0 commit comments

Comments
 (0)