# Buggy code
def write_array(self, key: str, value: ArrayLike, items: Optional[Index] = None):
    # TODO: we only have one test that gets here, the only EA
    #  that gets passed is DatetimeArray, and we never have
    #  both self._filters and EA
    assert isinstance(value, (np.ndarray, ABCExtensionArray)), type(value)

    if key in self.group:
        self._handle.remove_node(self.group, key)

    # Transform needed to interface with pytables row/col notation
    empty_array = value.size == 0
    transposed = False

    if is_categorical_dtype(value.dtype):
        raise NotImplementedError(
            "Cannot store a category dtype in a HDF5 dataset that uses format="
            '"fixed". Use format="table".'
        )
    if not empty_array:
        if hasattr(value, "T"):
            # ExtensionArrays (1d) may not have transpose.
            value = value.T
            transposed = True

    atom = None
    if self._filters is not None:
        with suppress(ValueError):
            # get the atom for this datatype
            atom = _tables().Atom.from_dtype(value.dtype)

    if atom is not None:
        # We only get here if self._filters is non-None and
        #  the Atom.from_dtype call succeeded

        # create an empty chunked array and fill it from value
        if not empty_array:
            ca = self._handle.create_carray(
                self.group, key, atom, value.shape, filters=self._filters
            )
            ca[:] = value

        else:
            self.write_array_empty(key, value)

    elif value.dtype.type == np.object_:
        # infer the type, warn if we have a non-string type here (for
        # performance)
        inferred_type = lib.infer_dtype(value, skipna=False)
        if empty_array:
            pass
        elif inferred_type == "string":
            pass
        else:
            ws = performance_doc % (inferred_type, key, items)
            warnings.warn(ws, PerformanceWarning, stacklevel=7)

        vlarr = self._handle.create_vlarray(self.group, key, _tables().ObjectAtom())
        vlarr.append(value)

    elif is_datetime64_dtype(value.dtype):
        self._handle.create_array(self.group, key, value.view("i8"))
        getattr(self.group, key)._v_attrs.value_type = "datetime64"
    elif is_datetime64tz_dtype(value.dtype):
        # store as UTC
        # with a zone
        self._handle.create_array(self.group, key, value.asi8)

        node = getattr(self.group, key)
        node._v_attrs.tz = _get_tz(value.tz)
        node._v_attrs.value_type = "datetime64"
    elif is_timedelta64_dtype(value.dtype):
        self._handle.create_array(self.group, key, value.view("i8"))
        getattr(self.group, key)._v_attrs.value_type = "timedelta64"
    elif empty_array:
        self.write_array_empty(key, value)
    else:
        self._handle.create_array(self.group, key, value)

    getattr(self.group, key)._v_attrs.transposed = transposed


# Traceback (TypeError)
In [1]: import pandas as pd
...:
...: def check_roundtrip(obj):
...:     with pd.HDFStore('test.h5', 'w') as store:
...:         store['obj'] = obj
...:         retrieved = store['obj']
...:         return obj.equals(retrieved)
...:
...: s = pd.Series([], dtype='datetime64[ns, UTC]')
...: t = pd.Series([0], dtype='datetime64[ns, UTC]')
...: df = pd.DataFrame({'A': s})

In [2]: print(check_roundtrip(s))
False

In [3]: print(check_roundtrip(t))
False

In [4]: print(check_roundtrip(df))

------------------------------------------------------------------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-57f1e9853bf6> in <module>()
----> 1 print(check_roundtrip(df))

<ipython-input-1-1d7fb84453e9> in check_roundtrip(obj)
4     with pd.HDFStore('test.h5', 'w') as store:
5         store['obj'] = obj
----> 6         retrieved = store['obj']
7         return obj.equals(retrieved)
8

/home/ashieh/.local/lib/python2.7/site-packages/pandas/io/pytables.pyc in __getitem__(self, key)
481
482     def __getitem__(self, key):
--> 483         return self.get(key)
484
485     def __setitem__(self, key, value):

/home/ashieh/.local/lib/python2.7/site-packages/pandas/io/pytables.pyc in get(self, key)
669         if group is None:
670             raise KeyError('No object named %s in the file' % key)
--> 671         return self._read_group(group)
672
673     def select(self, key, where=None, start=None, stop=None, columns=None,

/home/ashieh/.local/lib/python2.7/site-packages/pandas/io/pytables.pyc in _read_group(self, group, **kwargs)
1347         s = self._create_storer(group)
1348         s.infer_axes()
-> 1349         return s.read(**kwargs)
1350
1351

/home/ashieh/.local/lib/python2.7/site-packages/pandas/io/pytables.pyc in read(self, start, stop, **kwargs)
2902             blk_items = self.read_index('block%d_items' % i)
2903             values = self.read_array('block%d_values' % i,
-> 2904                                      start=_start, stop=_stop)
2905             blk = make_block(values,
2906                              placement=items.get_indexer(blk_items))

/home/ashieh/.local/lib/python2.7/site-packages/pandas/io/pytables.pyc in read_array(self, key, start, stop)
2464             if shape is not None:
2465                 # length 0 axis
-> 2466                 ret = np.empty(shape, dtype=dtype)
2467             else:
2468                 ret = node[start:stop]

TypeError: Invalid datetime unit in metadata string "[ns, UTC]"

# Fixed code
def write_array(self, key: str, obj: FrameOrSeries, items: Optional[Index] = None):
    # TODO: we only have a few tests that get here, the only EA
    #  that gets passed is DatetimeArray, and we never have
    #  both self._filters and EA

    value = extract_array(obj, extract_numpy=True)

    if key in self.group:
        self._handle.remove_node(self.group, key)

    # Transform needed to interface with pytables row/col notation
    empty_array = value.size == 0
    transposed = False

    if is_categorical_dtype(value.dtype):
        raise NotImplementedError(
            "Cannot store a category dtype in a HDF5 dataset that uses format="
            '"fixed". Use format="table".'
        )
    if not empty_array:
        if hasattr(value, "T"):
            # ExtensionArrays (1d) may not have transpose.
            value = value.T
            transposed = True

    atom = None
    if self._filters is not None:
        with suppress(ValueError):
            # get the atom for this datatype
            atom = _tables().Atom.from_dtype(value.dtype)

    if atom is not None:
        # We only get here if self._filters is non-None and
        #  the Atom.from_dtype call succeeded

        # create an empty chunked array and fill it from value
        if not empty_array:
            ca = self._handle.create_carray(
                self.group, key, atom, value.shape, filters=self._filters
            )
            ca[:] = value

        else:
            self.write_array_empty(key, value)

    elif value.dtype.type == np.object_:
        # infer the type, warn if we have a non-string type here (for
        # performance)
        inferred_type = lib.infer_dtype(value, skipna=False)
        if empty_array:
            pass
        elif inferred_type == "string":
            pass
        else:
            ws = performance_doc % (inferred_type, key, items)
            warnings.warn(ws, PerformanceWarning, stacklevel=7)

        vlarr = self._handle.create_vlarray(self.group, key, _tables().ObjectAtom())
        vlarr.append(value)

    elif is_datetime64_dtype(value.dtype):
        self._handle.create_array(self.group, key, value.view("i8"))
        getattr(self.group, key)._v_attrs.value_type = "datetime64"
    elif is_datetime64tz_dtype(value.dtype):
        # store as UTC
        # with a zone
        self._handle.create_array(self.group, key, value.asi8)

        node = getattr(self.group, key)
        node._v_attrs.tz = _get_tz(value.tz)
        node._v_attrs.value_type = "datetime64"
    elif is_timedelta64_dtype(value.dtype):
        self._handle.create_array(self.group, key, value.view("i8"))
        getattr(self.group, key)._v_attrs.value_type = "timedelta64"
    elif empty_array:
        self.write_array_empty(key, value)
    else:
        self._handle.create_array(self.group, key, value)

    getattr(self.group, key)._v_attrs.transposed = transposed