diff --git a/docs/whats-new.rst b/docs/whats-new.rst index ed76a920..b753b298 100644 --- a/docs/whats-new.rst +++ b/docs/whats-new.rst @@ -5,7 +5,6 @@ What's new 0.4 (*unreleased*) ------------------ - adopt `SPEC0 `_ (:pull:`228`) - By `Justus Magin `_. This means that the supported versions change: @@ -18,8 +17,11 @@ What's new pint 0.16 0.19 ============ ============== ============== + By `Justus Magin `_. - add support for python 3.11 (:pull:`228`) By `Justus Magin `_. +- ignore datetime units on attributes (:pull:`241`) + By `Justus Magin `_. 0.3 (27 Jul 2022) ----------------- diff --git a/pint_xarray/accessors.py b/pint_xarray/accessors.py index 08183ed1..5cba6c8f 100644 --- a/pint_xarray/accessors.py +++ b/pint_xarray/accessors.py @@ -258,6 +258,12 @@ def quantify(self, units=_default, unit_registry=None, **unit_kwargs): ``xarray`` changes the way it implements indexes, these units will be set as attributes. + .. note:: + Also note that datetime units (i.e. ones that match + ``{units} since {date}``) in unit attributes will be + ignored, to avoid interfering with ``xarray``'s datetime + encoding / decoding. + Parameters ---------- units : unit-like or mapping of hashable to unit-like, optional @@ -984,6 +990,12 @@ def quantify(self, units=_default, unit_registry=None, **unit_kwargs): ``xarray`` changes the way it implements indexes, these units will be set as attributes. + .. note:: + Also note that datetime units (i.e. ones that match + ``{units} since {date}``) in unit attributes will be + ignored, to avoid interfering with ``xarray``'s datetime + encoding / decoding. + Parameters ---------- units : mapping of hashable to unit-like, optional diff --git a/pint_xarray/conversion.py b/pint_xarray/conversion.py index b18b8a63..b7ac292c 100644 --- a/pint_xarray/conversion.py +++ b/pint_xarray/conversion.py @@ -1,4 +1,5 @@ import itertools +import re import pint from xarray import DataArray, Dataset, IndexVariable, Variable @@ -11,6 +12,14 @@ slice_attributes = ("start", "stop", "step") temporary_name = "" +time_units_re = r"\w+" +datetime_re = r"\d{4}-\d{2}-\d{2}(?:[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?)?" +datetime_units_re = re.compile(rf"{time_units_re} since {datetime_re}") + + +def is_datetime_unit(unit): + return isinstance(unit, str) and datetime_units_re.match(unit) is not None + def array_attach_units(data, unit): """attach a unit to the data @@ -266,7 +275,11 @@ def extract_units(obj): def extract_unit_attributes_dataset(obj, attr="units"): - return {name: var.attrs.get(attr, None) for name, var in obj.variables.items()} + all_units = {name: var.attrs.get(attr, None) for name, var in obj.variables.items()} + + return { + name: unit for name, unit in all_units.items() if not is_datetime_unit(unit) + } def extract_unit_attributes(obj, attr="units"): @@ -308,6 +321,9 @@ def strip_units(obj): def strip_unit_attributes_dataset(obj, attr="units"): new_obj = obj.copy() for var in new_obj.variables.values(): + if is_datetime_unit(var.attrs.get(attr, "")): + continue + var.attrs.pop(attr, None) return new_obj diff --git a/pint_xarray/tests/test_conversion.py b/pint_xarray/tests/test_conversion.py index 20c4f5cf..c4dd4585 100644 --- a/pint_xarray/tests/test_conversion.py +++ b/pint_xarray/tests/test_conversion.py @@ -482,6 +482,11 @@ def test_extract_units(self, type, units): {"a": "K", "b": "hPa", "x": "m", "u": "s"}, id="Dataset", ), + pytest.param( + Dataset(coords={"t": ("t", [], {"units": "seconds since 2000-01-01"})}), + {}, + id="datetime_unit", + ), ), ) def test_extract_unit_attributes(self, obj, expected): @@ -546,6 +551,11 @@ def test_strip_units(self, obj, expected): {"a": "K", "b": "hPa", "x": "m", "u": "s"}, id="Dataset", ), + pytest.param( + Dataset(coords={"t": ("t", [], {"units": "seconds since 2000-01-01"})}), + {}, + id="datetime_unit", + ), ), ) def test_strip_unit_attributes(self, obj, expected):