Skip to content

Commit ddec6ea

Browse files
authored
ignore datetime units (#241)
* add a predicate to check if a unit is for datetime decoding * skip the unit attributes if the unit string is a datetime unit * don't strip datetime units * make sure to only try matching unit strings * add tests for the modification * what's new entry * mention this behavior in the docstring of `.quantify`
1 parent 41aeb5f commit ddec6ea

File tree

4 files changed

+42
-2
lines changed

4 files changed

+42
-2
lines changed

docs/whats-new.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ What's new
55
0.4 (*unreleased*)
66
------------------
77
- adopt `SPEC0 <https://scientific-python.org/specs/spec-0000>`_ (:pull:`228`)
8-
By `Justus Magin <https://github.com/keewis>`_.
98

109
This means that the supported versions change:
1110

@@ -18,8 +17,11 @@ What's new
1817
pint 0.16 0.19
1918
============ ============== ==============
2019

20+
By `Justus Magin <https://github.com/keewis>`_.
2121
- add support for python 3.11 (:pull:`228`)
2222
By `Justus Magin <https://github.com/keewis>`_.
23+
- ignore datetime units on attributes (:pull:`241`)
24+
By `Justus Magin <https://github.com/keewis>`_.
2325

2426
0.3 (27 Jul 2022)
2527
-----------------

pint_xarray/accessors.py

+12
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,12 @@ def quantify(self, units=_default, unit_registry=None, **unit_kwargs):
258258
``xarray`` changes the way it implements indexes, these
259259
units will be set as attributes.
260260
261+
.. note::
262+
Also note that datetime units (i.e. ones that match
263+
``{units} since {date}``) in unit attributes will be
264+
ignored, to avoid interfering with ``xarray``'s datetime
265+
encoding / decoding.
266+
261267
Parameters
262268
----------
263269
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):
984990
``xarray`` changes the way it implements indexes, these
985991
units will be set as attributes.
986992
993+
.. note::
994+
Also note that datetime units (i.e. ones that match
995+
``{units} since {date}``) in unit attributes will be
996+
ignored, to avoid interfering with ``xarray``'s datetime
997+
encoding / decoding.
998+
987999
Parameters
9881000
----------
9891001
units : mapping of hashable to unit-like, optional

pint_xarray/conversion.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import itertools
2+
import re
23

34
import pint
45
from xarray import DataArray, Dataset, IndexVariable, Variable
@@ -11,6 +12,14 @@
1112
slice_attributes = ("start", "stop", "step")
1213
temporary_name = "<this-array>"
1314

15+
time_units_re = r"\w+"
16+
datetime_re = r"\d{4}-\d{2}-\d{2}(?:[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?)?"
17+
datetime_units_re = re.compile(rf"{time_units_re} since {datetime_re}")
18+
19+
20+
def is_datetime_unit(unit):
21+
return isinstance(unit, str) and datetime_units_re.match(unit) is not None
22+
1423

1524
def array_attach_units(data, unit):
1625
"""attach a unit to the data
@@ -266,7 +275,11 @@ def extract_units(obj):
266275

267276

268277
def extract_unit_attributes_dataset(obj, attr="units"):
269-
return {name: var.attrs.get(attr, None) for name, var in obj.variables.items()}
278+
all_units = {name: var.attrs.get(attr, None) for name, var in obj.variables.items()}
279+
280+
return {
281+
name: unit for name, unit in all_units.items() if not is_datetime_unit(unit)
282+
}
270283

271284

272285
def extract_unit_attributes(obj, attr="units"):
@@ -308,6 +321,9 @@ def strip_units(obj):
308321
def strip_unit_attributes_dataset(obj, attr="units"):
309322
new_obj = obj.copy()
310323
for var in new_obj.variables.values():
324+
if is_datetime_unit(var.attrs.get(attr, "")):
325+
continue
326+
311327
var.attrs.pop(attr, None)
312328

313329
return new_obj

pint_xarray/tests/test_conversion.py

+10
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,11 @@ def test_extract_units(self, type, units):
482482
{"a": "K", "b": "hPa", "x": "m", "u": "s"},
483483
id="Dataset",
484484
),
485+
pytest.param(
486+
Dataset(coords={"t": ("t", [], {"units": "seconds since 2000-01-01"})}),
487+
{},
488+
id="datetime_unit",
489+
),
485490
),
486491
)
487492
def test_extract_unit_attributes(self, obj, expected):
@@ -546,6 +551,11 @@ def test_strip_units(self, obj, expected):
546551
{"a": "K", "b": "hPa", "x": "m", "u": "s"},
547552
id="Dataset",
548553
),
554+
pytest.param(
555+
Dataset(coords={"t": ("t", [], {"units": "seconds since 2000-01-01"})}),
556+
{},
557+
id="datetime_unit",
558+
),
549559
),
550560
)
551561
def test_strip_unit_attributes(self, obj, expected):

0 commit comments

Comments
 (0)