@@ -308,6 +308,21 @@ cdef convert_to_timedelta64(object ts, str unit):
308
308
return ts.astype("timedelta64[ns]")
309
309
310
310
311
+ cpdef to_timedelta64(object value, str unit):
312
+ """
313
+ Wrapper around convert_to_timedelta64() that does overflow checks.
314
+ TODO: also construct non-nano
315
+ TODO: do all overflow-unsafe operations here
316
+ TODO: constrain unit to a more specific type
317
+ """
318
+ with cython.overflowcheck(True):
319
+ try:
320
+ return convert_to_timedelta64(value, unit)
321
+ except OverflowError as ex:
322
+ msg = f"{value} outside allowed range [{TIMEDELTA_MIN_NS}ns, {TIMEDELTA_MAX_NS}ns]"
323
+ raise OutOfBoundsTimedelta(msg) from ex
324
+
325
+
311
326
@cython.boundscheck(False)
312
327
@cython.wraparound(False)
313
328
def array_to_timedelta64(
@@ -1473,49 +1488,44 @@ class Timedelta(_Timedelta):
1473
1488
)
1474
1489
if isinstance(value, str) and unit is not None:
1475
1490
raise ValueError("unit must not be specified if the value is a str")
1476
- elif value is _no_input:
1477
- if not kwargs:
1478
- raise ValueError(
1479
- "cannot construct a Timedelta without a value/unit "
1480
- "or descriptive keywords (days,seconds....)"
1481
- )
1482
- if not kwargs.keys() <= set(cls._allowed_kwargs):
1483
- raise ValueError(
1484
- "cannot construct a Timedelta from the passed arguments, "
1485
- f"allowed keywords are {cls._allowed_kwargs}"
1486
- )
1491
+ elif value is _no_input and not kwargs:
1492
+ raise ValueError(
1493
+ "cannot construct a Timedelta without a value/unit "
1494
+ "or descriptive keywords (days,seconds....)"
1495
+ )
1496
+ if not kwargs.keys() <= set(cls._allowed_kwargs):
1497
+ raise ValueError(
1498
+ "cannot construct a Timedelta from the passed arguments, "
1499
+ f"allowed keywords are {cls._allowed_kwargs}"
1500
+ )
1487
1501
1488
- try:
1489
- # GH43764, convert any input to nanoseconds first, to ensure any potential
1490
- # nanosecond contributions from kwargs parsed as floats are included
1491
- kwargs = collections.defaultdict(int, {key: _to_py_int_float(val) for key, val in kwargs.items()})
1492
- if kwargs:
1493
- value = convert_to_timedelta64(
1494
- sum((
1495
- kwargs["weeks"] * 7 * 24 * 3600 * 1_000_000_000,
1496
- kwargs["days"] * 24 * 3600 * 1_000_000_000,
1497
- kwargs["hours"] * 3600 * 1_000_000_000,
1498
- kwargs["minutes"] * 60 * 1_000_000_000,
1499
- kwargs["seconds"] * 1_000_000_000,
1500
- kwargs["milliseconds"] * 1_000_000,
1501
- kwargs["microseconds"] * 1_000,
1502
- kwargs["nanoseconds"],
1503
- )),
1504
- "ns",
1505
- )
1506
- else:
1507
- if is_integer_object(value) or is_float_object(value):
1508
- unit = parse_timedelta_unit(unit)
1509
- else:
1510
- unit = "ns"
1511
- value = convert_to_timedelta64(value, unit)
1512
- except OverflowError as ex:
1513
- msg = f"outside allowed range [{TIMEDELTA_MIN_NS}ns, {TIMEDELTA_MAX_NS}ns]"
1514
- raise OutOfBoundsTimedelta(msg) from ex
1502
+ # GH43764, convert any input to nanoseconds first, to ensure any potential
1503
+ # nanosecond contributions from kwargs parsed as floats are included
1504
+ kwargs = collections.defaultdict(int, {key: _to_py_int_float(val) for key, val in kwargs.items()})
1505
+ if kwargs:
1506
+ value = to_timedelta64(
1507
+ sum((
1508
+ kwargs["weeks"] * 7 * 24 * 3600 * 1_000_000_000,
1509
+ kwargs["days"] * 24 * 3600 * 1_000_000_000,
1510
+ kwargs["hours"] * 3600 * 1_000_000_000,
1511
+ kwargs["minutes"] * 60 * 1_000_000_000,
1512
+ kwargs["seconds"] * 1_000_000_000,
1513
+ kwargs["milliseconds"] * 1_000_000,
1514
+ kwargs["microseconds"] * 1_000,
1515
+ kwargs["nanoseconds"],
1516
+ )),
1517
+ "ns",
1518
+ )
1515
1519
else:
1516
- if is_td64nat(value):
1517
- return NaT
1518
- return _timedelta_from_value_and_reso(value.view("i8"), NPY_FR_ns)
1520
+ if is_integer_object(value) or is_float_object(value):
1521
+ unit = parse_timedelta_unit(unit)
1522
+ else:
1523
+ unit = "ns"
1524
+ value = to_timedelta64(value, unit)
1525
+
1526
+ if is_td64nat(value):
1527
+ return NaT
1528
+ return _timedelta_from_value_and_reso(value.view("i8"), NPY_FR_ns)
1519
1529
1520
1530
def __setstate__(self, state):
1521
1531
if len(state) == 1:
0 commit comments