@@ -365,6 +365,21 @@ def _check_date_for_units_since_refdate(
365
365
return pd .Timestamp ("NaT" )
366
366
367
367
368
+ def _check_timedelta_range (value , data_unit , time_unit ):
369
+ if value > np .iinfo ("int64" ).max or value < np .iinfo ("int64" ).min :
370
+ OutOfBoundsTimedelta (f"Value { value } can't be represented as Timedelta." )
371
+ delta = value * np .timedelta64 (1 , data_unit )
372
+ if not np .isnan (delta ):
373
+ # this will raise on dtype overflow for integer dtypes
374
+ if value .dtype .kind in "u" and not np .int64 (delta ) == value :
375
+ raise OutOfBoundsTimedelta (
376
+ "DType overflow in Datetime/Timedelta calculation."
377
+ )
378
+ # this will raise on overflow if delta cannot be represented with the
379
+ # resolutions supported by pandas.
380
+ pd .to_timedelta (delta )
381
+
382
+
368
383
def _align_reference_date_and_unit (
369
384
ref_date : pd .Timestamp , unit : NPDatetimeUnitOptions
370
385
) -> pd .Timestamp :
@@ -542,19 +557,6 @@ def decode_cf_datetime(
542
557
return reshape (dates , num_dates .shape )
543
558
544
559
545
- def to_timedelta_unboxed (value , ** kwargs ):
546
- # todo: check, if the procedure here is correct
547
- result = pd .to_timedelta (value , ** kwargs ).to_numpy ()
548
- unique_timedeltas = np .unique (result [pd .notnull (result )])
549
- unit = _netcdf_to_numpy_timeunit (_infer_time_units_from_diff (unique_timedeltas ))
550
- if unit not in {"s" , "ms" , "us" , "ns" }:
551
- # default to "ns", when not specified
552
- unit = "ns"
553
- result = result .astype (f"timedelta64[{ unit } ]" )
554
- assert np .issubdtype (result .dtype , "timedelta64" )
555
- return result
556
-
557
-
558
560
def to_datetime_unboxed (value , ** kwargs ):
559
561
result = pd .to_datetime (value , ** kwargs ).to_numpy ()
560
562
assert np .issubdtype (result .dtype , "datetime64" )
@@ -604,22 +606,36 @@ def _numbers_to_timedelta(
604
606
return flat_num .astype (f"timedelta64[{ time_unit } ]" )
605
607
606
608
607
- def decode_cf_timedelta (num_timedeltas , units : str ) -> np .ndarray :
608
- # todo: check, if this works as intended
609
+ def decode_cf_timedelta (
610
+ num_timedeltas , units : str , time_unit : str = "ns"
611
+ ) -> np .ndarray :
609
612
"""Given an array of numeric timedeltas in netCDF format, convert it into a
610
613
numpy timedelta64 ["s", "ms", "us", "ns"] array.
611
614
"""
612
615
num_timedeltas = np .asarray (num_timedeltas )
613
616
unit = _netcdf_to_numpy_timeunit (units )
614
617
618
+ _check_timedelta_range (num_timedeltas .min (), unit , time_unit )
619
+ _check_timedelta_range (num_timedeltas .max (), unit , time_unit )
620
+
615
621
timedeltas = _numbers_to_timedelta (num_timedeltas , unit , "s" , "timedelta" )
622
+ timedeltas = pd .to_timedelta (ravel (timedeltas ))
623
+
624
+ if np .isnat (timedeltas ).all ():
625
+ empirical_unit = time_unit
626
+ else :
627
+ empirical_unit = timedeltas .unit
628
+
629
+ if np .timedelta64 (1 , time_unit ) > np .timedelta64 (1 , empirical_unit ):
630
+ time_unit = empirical_unit
631
+
632
+ if time_unit not in {"s" , "ms" , "us" , "ns" }:
633
+ raise ValueError (
634
+ f"time_unit must be one of 's', 'ms', 'us', or 'ns'. Got: { time_unit } "
635
+ )
616
636
617
- as_unit = unit
618
- if unit not in {"s" , "ms" , "us" , "ns" }:
619
- # default to "ns", when not specified
620
- as_unit = "ns"
621
- result = pd .to_timedelta (ravel (timedeltas )).as_unit (as_unit ).to_numpy ()
622
- return reshape (result , timedeltas .shape )
637
+ result = timedeltas .as_unit (time_unit ).to_numpy ()
638
+ return reshape (result , num_timedeltas .shape )
623
639
624
640
625
641
def _unit_timedelta_cftime (units : str ) -> timedelta :
@@ -700,7 +716,7 @@ def infer_timedelta_units(deltas) -> str:
700
716
{'days', 'hours', 'minutes' 'seconds'} (the first one that can evenly
701
717
divide all unique time deltas in `deltas`)
702
718
"""
703
- deltas = to_timedelta_unboxed ( ravel (np . asarray ( deltas )) )
719
+ deltas = ravel (deltas )
704
720
unique_timedeltas = np .unique (deltas [pd .notnull (deltas )])
705
721
return _infer_time_units_from_diff (unique_timedeltas )
706
722
0 commit comments