Skip to content

Commit 74e9d72

Browse files
committed
Support nano second time encoding.
1 parent 55480de commit 74e9d72

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

xarray/coding/times.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
_STANDARD_CALENDARS = {"standard", "gregorian", "proleptic_gregorian"}
2727

2828
_NS_PER_TIME_DELTA = {
29+
"ns": int(1e0),
2930
"us": int(1e3),
3031
"ms": int(1e6),
3132
"s": int(1e9),
@@ -35,7 +36,15 @@
3536
}
3637

3738
TIME_UNITS = frozenset(
38-
["days", "hours", "minutes", "seconds", "milliseconds", "microseconds"]
39+
[
40+
"days",
41+
"hours",
42+
"minutes",
43+
"seconds",
44+
"milliseconds",
45+
"microseconds",
46+
"nanoseconds",
47+
]
3948
)
4049

4150

@@ -44,6 +53,7 @@ def _netcdf_to_numpy_timeunit(units):
4453
if not units.endswith("s"):
4554
units = "%ss" % units
4655
return {
56+
"nanoseconds": "ns",
4757
"microseconds": "us",
4858
"milliseconds": "ms",
4959
"seconds": "s",

xarray/tests/test_backends.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4601,3 +4601,40 @@ def test_extract_zarr_variable_encoding():
46014601
actual = backends.zarr.extract_zarr_variable_encoding(
46024602
var, raise_on_invalid=True
46034603
)
4604+
4605+
4606+
@requires_netCDF4
4607+
def test_cftime_nanosecond(tmp_path):
4608+
import netCDF4
4609+
4610+
time_data = xr.DataArray(
4611+
np.asarray(
4612+
["2020-09-01T00:00:00.000000", "2020-09-01T00:00:00.586001"],
4613+
dtype=np.datetime64,
4614+
),
4615+
name="time",
4616+
)
4617+
filename = str(tmp_path / "time.nc")
4618+
4619+
time_data.to_netcdf(filename)
4620+
with netCDF4.Dataset(filename, mode="r") as loaded:
4621+
# Prior to 0.10.9, the time encoding for objects with nano second
4622+
# deltas was in seconds, but use floating point to attempt to maintain
4623+
# the difference
4624+
assert loaded["time"].units.startswith("seconds")
4625+
assert loaded["time"].dtype == np.float64
4626+
4627+
time_data.encoding = {
4628+
"units": "nanoseconds since 2020-09-01",
4629+
"calendar": "proleptic_gregorian",
4630+
}
4631+
time_data.to_netcdf(filename)
4632+
with netCDF4.Dataset(filename, mode="r") as loaded:
4633+
# Prior to 0.10.9, the time encoding for objects with nano second
4634+
# deltas was in seconds, but use floating point to attempt to maintain
4635+
# the difference
4636+
assert loaded["time"].units.startswith("nanoseconds")
4637+
assert loaded["time"].dtype == np.int64
4638+
4639+
time_data_loaded = xr.load_dataarray(filename)
4640+
assert_equal(time_data, time_data_loaded)

xarray/tests/test_coding_times.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
([0.5, 1.5], "hours since 1900-01-01T00:00:00"),
5959
(0, "milliseconds since 2000-01-01T00:00:00"),
6060
(0, "microseconds since 2000-01-01T00:00:00"),
61+
# 2020/09/01: hmaarrfk: cftime/_cftime.pyx doesn't support nanosecond
62+
# (0, "nanoseconds since 2000-01-01T00:00:00"),
6163
(np.int32(788961600), "seconds since 1981-01-01"), # GH2002
6264
(12300 + np.arange(5), "hour since 1680-01-01 00:00:00.500000"),
6365
]
@@ -537,6 +539,7 @@ def test_infer_cftime_datetime_units(calendar, date_args, expected):
537539
("1h", "hours", np.int64(1)),
538540
("1ms", "milliseconds", np.int64(1)),
539541
("1us", "microseconds", np.int64(1)),
542+
("1ns", "nanoseconds", np.int64(1)),
540543
(["NaT", "0s", "1s"], None, [np.nan, 0, 1]),
541544
(["30m", "60m"], "hours", [0.5, 1.0]),
542545
("NaT", "days", np.nan),

0 commit comments

Comments
 (0)