@@ -887,11 +887,26 @@ cdef object create_timedelta(object value, str in_unit, NPY_DATETIMEUNIT out_res
887
887
"""
888
888
Timedelta factory.
889
889
890
- Timedelta.__new__ just does arg validation (at least currently). Also, some internal
891
- functions expect to be able to create non-nano reso Timedeltas, but Timedelta.__new__
892
- doesn't yet expose that .
890
+ Overflow-safe, and allows for the creation of Timedeltas with non-nano resos while
891
+ the public API for that gets hashed out (ref: GH#46587). For now, Timedelta.__new__
892
+ just does arg validation and kwarg processing .
893
893
894
- _timedelta_from_value_and_reso does, but only accepts limited args, and doesn't check for overflow.
894
+ _timedelta_from_value_and_reso faster if value already an int that can be safely
895
+ cast to an int64.
896
+
897
+ Parameters
898
+ ----------
899
+ value : Timedelta, timedelta, np.timedelta64, str, int, float
900
+ The same value types accepted by Timedelta.__new__
901
+ in_unit : str
902
+ Denote the (np) unit of the input, if it's numeric
903
+ out_reso: NPY_DATETIMEUNIT
904
+ Desired resolution of new Timedelta
905
+
906
+ Notes
907
+ -----
908
+ Pass in_unit="ignore" (or "ns") with a numeric value to just do overflow checking
909
+ (and bypass the prior behavior of converting value -> td64[ns] -> int)
895
910
"""
896
911
cdef:
897
912
int64_t out_value
@@ -903,12 +918,14 @@ cdef object create_timedelta(object value, str in_unit, NPY_DATETIMEUNIT out_res
903
918
# if unit == "ns", no need to create an m8[ns] just to read the (same) value back
904
919
# if unit == "ignore", assume caller wants to invoke an overflow-safe version of
905
920
# _timedelta_from_value_and_reso, and that any float rounding is acceptable
906
- if (is_integer_object(value) or is_float_object(value)) and (in_unit == " ns" or in_unit == " ignore" ):
921
+ if (is_integer_object(value) or is_float_object(value)) and (
922
+ in_unit == " ns" or in_unit == " ignore"
923
+ ):
907
924
if util.is_nan(value):
908
925
return NaT
909
926
out_value = < int64_t> value
910
- # is_timedelta_64_object may not give correct results w/ some versions?
911
- # see e.g. https:// github.com/pandas-dev/pandas/runs/6397652653?check_suite_focus=true#step:11:435
927
+ # is_timedelta_64_object may not give correct results w/ some versions? see e.g.
928
+ # github.com/pandas-dev/pandas/runs/6397652653?check_suite_focus=true#step:11:435
912
929
elif isinstance (value, np.timedelta64):
913
930
out_value = ensure_td64ns(value).view(np.int64)
914
931
elif isinstance (value, str ):
@@ -1474,7 +1491,8 @@ class Timedelta(_Timedelta):
1474
1491
"""
1475
1492
1476
1493
_allowed_kwargs = (
1477
- " weeks" , " days" , " hours" , " minutes" , " seconds" , " milliseconds" , " microseconds" , " nanoseconds"
1494
+ " weeks" , " days" , " hours" , " minutes" , " seconds" , " milliseconds" , " microseconds" ,
1495
+ " nanoseconds"
1478
1496
)
1479
1497
1480
1498
def __new__ (cls , object value = _no_input, unit = None , **kwargs ):
@@ -1495,19 +1513,16 @@ class Timedelta(_Timedelta):
1495
1513
)
1496
1514
# GH43764, convert any input to nanoseconds first, to ensure any potential
1497
1515
# nanosecond contributions from kwargs parsed as floats are included
1498
- # kwargs = collections.defaultdict(int, {key: _to_py_int_float(val) for key, val in kwargs.items()})
1499
- ns = sum (
1500
- (
1501
- _to_py_int_float(kwargs.get(" weeks" , 0 )) * 7 * 24 * 3600 * 1 _000_000_000,
1502
- _to_py_int_float(kwargs.get(" days" , 0 )) * 24 * 3600 * 1 _000_000_000,
1503
- _to_py_int_float(kwargs.get(" hours" , 0 )) * 3600 * 1 _000_000_000,
1504
- _to_py_int_float(kwargs.get(" minutes" , 0 )) * 60 * 1 _000_000_000,
1505
- _to_py_int_float(kwargs.get(" seconds" , 0 )) * 1 _000_000_000,
1506
- _to_py_int_float(kwargs.get(" milliseconds" , 0 )) * 1 _000_000,
1507
- _to_py_int_float(kwargs.get(" microseconds" , 0 )) * 1 _000,
1508
- _to_py_int_float(kwargs.get(" nanoseconds" , 0 )),
1509
- )
1510
- )
1516
+ ns = sum ((
1517
+ _to_py_int_float(kwargs.get(" weeks" , 0 )) * 7 * 24 * 3600 * 1 _000_000_000,
1518
+ _to_py_int_float(kwargs.get(" days" , 0 )) * 24 * 3600 * 1 _000_000_000,
1519
+ _to_py_int_float(kwargs.get(" hours" , 0 )) * 3600 * 1 _000_000_000,
1520
+ _to_py_int_float(kwargs.get(" minutes" , 0 )) * 60 * 1 _000_000_000,
1521
+ _to_py_int_float(kwargs.get(" seconds" , 0 )) * 1 _000_000_000,
1522
+ _to_py_int_float(kwargs.get(" milliseconds" , 0 )) * 1 _000_000,
1523
+ _to_py_int_float(kwargs.get(" microseconds" , 0 )) * 1 _000,
1524
+ _to_py_int_float(kwargs.get(" nanoseconds" , 0 )),
1525
+ ))
1511
1526
return create_timedelta(ns, " ns" , out_reso)
1512
1527
1513
1528
if isinstance (value, str ) and unit is not None :
0 commit comments