9
9
from numpy import array , nan
10
10
11
11
from xarray import DataArray , Dataset , cftime_range , concat
12
+ from xarray .coding .times import _NS_PER_TIME_DELTA
12
13
from xarray .core import dtypes , duck_array_ops
13
14
from xarray .core .duck_array_ops import (
14
15
array_notnull_equiv ,
28
29
where ,
29
30
)
30
31
from xarray .core .extension_array import PandasExtensionArray
32
+ from xarray .core .types import NPDatetimeUnitOptions , PDDatetimeUnitOptions
31
33
from xarray .namedarray .pycompat import array_type
32
34
from xarray .testing import assert_allclose , assert_equal , assert_identical
33
35
from xarray .tests import (
@@ -411,10 +413,11 @@ def assert_dask_array(da, dask):
411
413
@arm_xfail
412
414
@pytest .mark .filterwarnings ("ignore:All-NaN .* encountered:RuntimeWarning" )
413
415
@pytest .mark .parametrize ("dask" , [False , True ] if has_dask else [False ])
414
- def test_datetime_mean (dask : bool ) -> None :
416
+ def test_datetime_mean (dask : bool , time_unit : PDDatetimeUnitOptions ) -> None :
415
417
# Note: only testing numpy, as dask is broken upstream
418
+ dtype = f"M8[{ time_unit } ]"
416
419
da = DataArray (
417
- np .array (["2010-01-01" , "NaT" , "2010-01-03" , "NaT" , "NaT" ], dtype = "M8[ns]" ),
420
+ np .array (["2010-01-01" , "NaT" , "2010-01-03" , "NaT" , "NaT" ], dtype = dtype ),
418
421
dims = ["time" ],
419
422
)
420
423
if dask :
@@ -846,11 +849,11 @@ def test_multiple_dims(dtype, dask, skipna, func):
846
849
847
850
848
851
@pytest .mark .parametrize ("dask" , [True , False ])
849
- def test_datetime_to_numeric_datetime64 (dask ):
852
+ def test_datetime_to_numeric_datetime64 (dask , time_unit : PDDatetimeUnitOptions ):
850
853
if dask and not has_dask :
851
854
pytest .skip ("requires dask" )
852
855
853
- times = pd .date_range ("2000" , periods = 5 , freq = "7D" ).values
856
+ times = pd .date_range ("2000" , periods = 5 , freq = "7D" ).as_unit ( time_unit ). values
854
857
if dask :
855
858
import dask .array
856
859
@@ -874,8 +877,8 @@ def test_datetime_to_numeric_datetime64(dask):
874
877
result = duck_array_ops .datetime_to_numeric (
875
878
times , datetime_unit = "h" , dtype = dtype
876
879
)
877
- expected = 24 * np .arange (0 , 35 , 7 ).astype (dtype )
878
- np .testing .assert_array_equal (result , expected )
880
+ expected2 = 24 * np .arange (0 , 35 , 7 ).astype (dtype )
881
+ np .testing .assert_array_equal (result , expected2 )
879
882
880
883
881
884
@requires_cftime
@@ -923,15 +926,18 @@ def test_datetime_to_numeric_cftime(dask):
923
926
924
927
925
928
@requires_cftime
926
- def test_datetime_to_numeric_potential_overflow ():
929
+ def test_datetime_to_numeric_potential_overflow (time_unit : PDDatetimeUnitOptions ):
927
930
import cftime
928
931
929
- times = pd .date_range ("2000" , periods = 5 , freq = "7D" ).values .astype ("datetime64[us]" )
932
+ if time_unit == "ns" :
933
+ pytest .skip ("out-of-bounds datetime64 overflow" )
934
+ dtype = f"M8[{ time_unit } ]"
935
+ times = pd .date_range ("2000" , periods = 5 , freq = "7D" ).values .astype (dtype )
930
936
cftimes = cftime_range (
931
937
"2000" , periods = 5 , freq = "7D" , calendar = "proleptic_gregorian"
932
938
).values
933
939
934
- offset = np .datetime64 ("0001-01-01" )
940
+ offset = np .datetime64 ("0001-01-01" , time_unit )
935
941
cfoffset = cftime .DatetimeProlepticGregorian (1 , 1 , 1 )
936
942
937
943
result = duck_array_ops .datetime_to_numeric (
@@ -957,35 +963,45 @@ def test_py_timedelta_to_float():
957
963
assert py_timedelta_to_float (dt .timedelta (days = 1e6 ), "D" ) == 1e6
958
964
959
965
960
- @pytest .mark .parametrize (
961
- "td, expected" ,
962
- ([np .timedelta64 (1 , "D" ), 86400 * 1e9 ], [np .timedelta64 (1 , "ns" ), 1.0 ]),
963
- )
964
- def test_np_timedelta64_to_float (td , expected ):
965
- out = np_timedelta64_to_float (td , datetime_unit = "ns" )
966
+ @pytest .mark .parametrize ("np_dt_unit" , ["D" , "h" , "m" , "s" , "ms" , "us" , "ns" ])
967
+ def test_np_timedelta64_to_float (
968
+ np_dt_unit : NPDatetimeUnitOptions , time_unit : PDDatetimeUnitOptions
969
+ ):
970
+ # tests any combination of source np.timedelta64 (NPDatetimeUnitOptions) with
971
+ # np_timedelta_to_float with dedicated target unit (PDDatetimeUnitOptions)
972
+ td = np .timedelta64 (1 , np_dt_unit )
973
+ expected = _NS_PER_TIME_DELTA [np_dt_unit ] / _NS_PER_TIME_DELTA [time_unit ]
974
+
975
+ out = np_timedelta64_to_float (td , datetime_unit = time_unit )
966
976
np .testing .assert_allclose (out , expected )
967
977
assert isinstance (out , float )
968
978
969
- out = np_timedelta64_to_float (np .atleast_1d (td ), datetime_unit = "ns" )
979
+ out = np_timedelta64_to_float (np .atleast_1d (td ), datetime_unit = time_unit )
970
980
np .testing .assert_allclose (out , expected )
971
981
972
982
973
- @pytest .mark .parametrize (
974
- "td, expected" , ([pd .Timedelta (1 , "D" ), 86400 * 1e9 ], [pd .Timedelta (1 , "ns" ), 1.0 ])
975
- )
976
- def test_pd_timedelta_to_float (td , expected ):
977
- out = pd_timedelta_to_float (td , datetime_unit = "ns" )
983
+ @pytest .mark .parametrize ("np_dt_unit" , ["D" , "h" , "m" , "s" , "ms" , "us" , "ns" ])
984
+ def test_pd_timedelta_to_float (
985
+ np_dt_unit : NPDatetimeUnitOptions , time_unit : PDDatetimeUnitOptions
986
+ ):
987
+ # tests any combination of source pd.Timedelta (NPDatetimeUnitOptions) with
988
+ # np_timedelta_to_float with dedicated target unit (PDDatetimeUnitOptions)
989
+ td = pd .Timedelta (1 , np_dt_unit )
990
+ expected = _NS_PER_TIME_DELTA [np_dt_unit ] / _NS_PER_TIME_DELTA [time_unit ]
991
+
992
+ out = pd_timedelta_to_float (td , datetime_unit = time_unit )
978
993
np .testing .assert_allclose (out , expected )
979
994
assert isinstance (out , float )
980
995
981
996
982
997
@pytest .mark .parametrize (
983
998
"td" , [dt .timedelta (days = 1 ), np .timedelta64 (1 , "D" ), pd .Timedelta (1 , "D" ), "1 day" ]
984
999
)
985
- def test_timedelta_to_numeric (td ):
1000
+ def test_timedelta_to_numeric (td , time_unit : PDDatetimeUnitOptions ):
986
1001
# Scalar input
987
- out = timedelta_to_numeric (td , "ns" )
988
- np .testing .assert_allclose (out , 86400 * 1e9 )
1002
+ out = timedelta_to_numeric (td , time_unit )
1003
+ expected = _NS_PER_TIME_DELTA ["D" ] / _NS_PER_TIME_DELTA [time_unit ]
1004
+ np .testing .assert_allclose (out , expected )
989
1005
assert isinstance (out , float )
990
1006
991
1007
0 commit comments