39
39
from xarray .coding .variables import SerializationWarning
40
40
from xarray .conventions import _update_bounds_attributes , cf_encoder
41
41
from xarray .core .common import contains_cftime_datetimes
42
+ from xarray .core .options import _get_datetime_resolution
42
43
from xarray .core .utils import is_duck_dask_array
43
44
from xarray .testing import assert_equal , assert_identical
44
45
from xarray .tests import (
@@ -134,7 +135,9 @@ def test_cf_datetime(num_dates, units, calendar) -> None:
134
135
max_y = np .ravel (np .atleast_1d (expected ))[np .nanargmax (num_dates )] # .year
135
136
typ = type (min_y )
136
137
border = typ (1582 , 10 , 15 )
137
- if calendar == "proleptic_gregorian" or (min_y >= border and max_y >= border ):
138
+ if (calendar == "proleptic_gregorian" and _get_datetime_resolution () != "ns" ) or (
139
+ min_y >= border and max_y >= border
140
+ ):
138
141
expected = cftime_to_nptime (expected )
139
142
140
143
with warnings .catch_warnings ():
@@ -214,12 +217,15 @@ def test_decode_standard_calendar_inside_timestamp_range(calendar) -> None:
214
217
import cftime
215
218
216
219
units = "days since 0001-01-01"
217
- unit = cast (Literal ["s" , "ms" , "us" , "ns" ], "us" )
220
+ unit = cast (Literal ["s" , "ms" , "us" , "ns" ], _get_datetime_resolution () )
218
221
times = pd .date_range ("2001-04-01-00" , end = "2001-04-30-23" , unit = unit , freq = "h" )
222
+ # to_pydatetime() will return microsecond
219
223
time = cftime .date2num (times .to_pydatetime (), units , calendar = calendar )
220
224
expected = times .values
221
- if calendar == "proleptic_gregorian" :
222
- unit = "s"
225
+ # for cftime we get "us" resolution
226
+ # ns resolution is handled by cftime, too (OutOfBounds)
227
+ if calendar != "proleptic_gregorian" or _get_datetime_resolution () == "ns" :
228
+ unit = "us"
223
229
expected_dtype = np .dtype (f"M8[{ unit } ]" )
224
230
actual = decode_cf_datetime (time , units , calendar = calendar )
225
231
assert actual .dtype == expected_dtype
@@ -268,7 +274,7 @@ def test_decode_dates_outside_timestamp_range(calendar) -> None:
268
274
time , units , calendar = calendar , only_use_cftime_datetimes = True
269
275
)
270
276
# special case proleptic_gregorian
271
- if calendar == "proleptic_gregorian" :
277
+ if calendar == "proleptic_gregorian" and _get_datetime_resolution () != "ns" :
272
278
expected = expected .astype ("=M8[us]" )
273
279
expected_date_type = type (expected [0 ])
274
280
@@ -289,7 +295,11 @@ def test_decode_standard_calendar_single_element_inside_timestamp_range(
289
295
calendar ,
290
296
) -> None :
291
297
units = "days since 0001-01-01"
292
- unit = "s" if calendar == "proleptic_gregorian" else "us"
298
+ unit = (
299
+ _get_datetime_resolution ()
300
+ if (calendar == "proleptic_gregorian" and _get_datetime_resolution () != "ns" )
301
+ else "us"
302
+ )
293
303
for num_time in [735368 , [735368 ], [[735368 ]]]:
294
304
with warnings .catch_warnings ():
295
305
warnings .filterwarnings ("ignore" , "Unable to decode time axis" )
@@ -337,7 +347,11 @@ def test_decode_standard_calendar_multidim_time_inside_timestamp_range(
337
347
import cftime
338
348
339
349
units = "days since 0001-01-01"
340
- unit = "s" if calendar == "proleptic_gregorian" else "us"
350
+ unit = (
351
+ _get_datetime_resolution ()
352
+ if (calendar == "proleptic_gregorian" and _get_datetime_resolution () != "ns" )
353
+ else "us"
354
+ )
341
355
times1 = pd .date_range ("2001-04-01" , end = "2001-04-05" , freq = "D" )
342
356
times2 = pd .date_range ("2001-05-01" , end = "2001-05-05" , freq = "D" )
343
357
time1 = cftime .date2num (times1 .to_pydatetime (), units , calendar = calendar )
@@ -426,8 +440,8 @@ def test_decode_multidim_time_outside_timestamp_range(calendar) -> None:
426
440
actual = decode_cf_datetime (mdim_time , units , calendar = calendar )
427
441
428
442
dtype : np .dtype
429
- if calendar == "proleptic_gregorian" :
430
- dtype = np .dtype ("=M8[s ]" )
443
+ if calendar == "proleptic_gregorian" and _get_datetime_resolution () != "ns" :
444
+ dtype = np .dtype (f "=M8[{ _get_datetime_resolution () } ]" )
431
445
expected1 = expected1 .astype (dtype )
432
446
expected2 = expected2 .astype (dtype )
433
447
else :
@@ -528,7 +542,7 @@ def test_decoded_cf_datetime_array_2d() -> None:
528
542
("x" , "y" ), np .array ([[0 , 1 ], [2 , 3 ]]), {"units" : "days since 2000-01-01" }
529
543
)
530
544
result = CFDatetimeCoder ().decode (variable )
531
- assert result .dtype == "datetime64[s ]"
545
+ assert result .dtype == f "datetime64[{ _get_datetime_resolution () } ]"
532
546
expected = pd .date_range ("2000-01-01" , periods = 4 ).values .reshape (2 , 2 )
533
547
assert_array_equal (np .asarray (result ), expected )
534
548
@@ -697,7 +711,7 @@ def test_decode_cf(calendar) -> None:
697
711
if calendar not in _STANDARD_CALENDARS :
698
712
assert ds .test .dtype == np .dtype ("O" )
699
713
else :
700
- assert ds .test .dtype == np .dtype ("M8[s ]" )
714
+ assert ds .test .dtype == np .dtype (f "M8[{ _get_datetime_resolution () } ]" )
701
715
702
716
703
717
def test_decode_cf_time_bounds () -> None :
@@ -722,7 +736,7 @@ def test_decode_cf_time_bounds() -> None:
722
736
"calendar" : "standard" ,
723
737
}
724
738
dsc = decode_cf (ds )
725
- assert dsc .time_bnds .dtype == np .dtype ("M8[s ]" )
739
+ assert dsc .time_bnds .dtype == np .dtype (f "M8[{ _get_datetime_resolution () } ]" )
726
740
dsc = decode_cf (ds , decode_times = False )
727
741
assert dsc .time_bnds .dtype == np .dtype ("int64" )
728
742
@@ -1299,7 +1313,11 @@ def test_roundtrip_datetime64_nanosecond_precision(
1299
1313
assert encoded_var .data .dtype == dtype
1300
1314
1301
1315
decoded_var = conventions .decode_cf_variable ("foo" , encoded_var )
1302
- assert decoded_var .dtype == np .dtype (f"=M8[{ timeunit } ]" )
1316
+ if _get_datetime_resolution () == "ns" :
1317
+ dtypeunit = "ns"
1318
+ else :
1319
+ dtypeunit = timeunit
1320
+ assert decoded_var .dtype == np .dtype (f"=M8[{ dtypeunit } ]" )
1303
1321
assert (
1304
1322
decoded_var .encoding ["units" ]
1305
1323
== f"{ _numpy_to_netcdf_timeunit (timeunit )} since 1970-01-01 00:00:00"
0 commit comments