@@ -42,6 +42,7 @@ from pandas._libs.tslibs.nattype cimport (
42
42
c_NaT as NaT,
43
43
c_nat_strings as nat_strings,
44
44
checknull_with_nat,
45
+ is_td64nat,
45
46
)
46
47
from pandas._libs.tslibs.np_datetime cimport (
47
48
NPY_DATETIMEUNIT,
@@ -1452,104 +1453,68 @@ class Timedelta(_Timedelta):
1452
1453
We see that either way we get the same result
1453
1454
"""
1454
1455
1455
- _req_any_kwargs_new = {" weeks" , " days" , " hours" , " minutes" , " seconds" ,
1456
- " milliseconds" , " microseconds" , " nanoseconds" }
1456
+ _allowed_kwargs = (
1457
+ " weeks" , " days" , " hours" , " minutes" , " seconds" , " milliseconds" , " microseconds" , " nanoseconds"
1458
+ )
1457
1459
1458
1460
def __new__ (cls , object value = _no_input, unit = None , **kwargs ):
1459
1461
cdef _Timedelta td_base
1460
1462
1461
- try :
1462
- if value is _no_input:
1463
- if not len (kwargs):
1464
- raise ValueError (" cannot construct a Timedelta without a "
1465
- " value/unit or descriptive keywords "
1466
- " (days,seconds....)" )
1467
-
1468
- kwargs = {key: _to_py_int_float(kwargs[key]) for key in kwargs}
1469
-
1470
- unsupported_kwargs = set (kwargs)
1471
- unsupported_kwargs.difference_update(cls ._req_any_kwargs_new)
1472
- if unsupported_kwargs or not cls ._req_any_kwargs_new.intersection(kwargs):
1473
- raise ValueError (
1474
- " cannot construct a Timedelta from the passed arguments, "
1475
- " allowed keywords are "
1476
- " [weeks, days, hours, minutes, seconds, "
1477
- " milliseconds, microseconds, nanoseconds]"
1478
- )
1479
-
1480
- # GH43764, convert any input to nanoseconds first and then
1481
- # create the timestamp. This ensures that any potential
1482
- # nanosecond contributions from kwargs parsed as floats
1483
- # are taken into consideration.
1484
- seconds = int ((
1485
- (
1486
- (kwargs.get(' days' , 0 ) + kwargs.get(' weeks' , 0 ) * 7 ) * 24
1487
- + kwargs.get(' hours' , 0 )
1488
- ) * 3600
1489
- + kwargs.get(' minutes' , 0 ) * 60
1490
- + kwargs.get(' seconds' , 0 )
1491
- ) * 1 _000_000_000
1492
- )
1463
+ if isinstance (value, _Timedelta):
1464
+ return value
1465
+ if checknull_with_nat(value):
1466
+ return NaT
1493
1467
1494
- value = np.timedelta64(
1495
- int (kwargs.get(' nanoseconds' , 0 ))
1496
- + int (kwargs.get(' microseconds' , 0 ) * 1 _000)
1497
- + int (kwargs.get(' milliseconds' , 0 ) * 1 _000_000)
1498
- + seconds
1468
+ if unit in {" Y" , " y" , " M" }:
1469
+ raise ValueError (
1470
+ " Units 'M', 'Y', and 'y' are no longer supported, as they do not "
1471
+ " represent unambiguous timedelta values durations."
1472
+ )
1473
+ if isinstance (value, str ) and unit is not None :
1474
+ raise ValueError (" unit must not be specified if the value is a str" )
1475
+ elif value is _no_input:
1476
+ if not kwargs:
1477
+ raise ValueError (
1478
+ " cannot construct a Timedelta without a value/unit "
1479
+ " or descriptive keywords (days,seconds....)"
1499
1480
)
1500
-
1501
- if unit in {' Y' , ' y' , ' M' }:
1481
+ if not kwargs.keys() <= set (cls ._allowed_kwargs):
1502
1482
raise ValueError (
1503
- " Units 'M', 'Y', and 'y' are no longer supported, as they do not "
1504
- " represent unambiguous timedelta values durations. "
1483
+ " cannot construct a Timedelta from the passed arguments, "
1484
+ f " allowed keywords are {cls._allowed_kwargs} "
1505
1485
)
1506
1486
1507
- # GH 30543 if pd.Timedelta already passed, return it
1508
- # check that only value is passed
1509
- if isinstance (value, _Timedelta) and unit is None and len (kwargs) == 0 :
1510
- return value
1511
- elif isinstance (value, _Timedelta):
1512
- value = value.value
1513
- elif isinstance (value, str ):
1514
- if unit is not None :
1515
- raise ValueError (" unit must not be specified if the value is a str" )
1516
- if (len (value) > 0 and value[0 ] == ' P' ) or (
1517
- len (value) > 1 and value[:2 ] == ' -P'
1518
- ):
1519
- value = parse_iso_format_string(value)
1487
+ try :
1488
+ # GH43764, convert any input to nanoseconds first, to ensure any potential
1489
+ # nanosecond contributions from kwargs parsed as floats are included
1490
+ kwargs = collections.defaultdict(int , {key: _to_py_int_float(val) for key, val in kwargs.items()})
1491
+ if kwargs:
1492
+ value = convert_to_timedelta64(
1493
+ sum ((
1494
+ kwargs[" weeks" ] * 7 * 24 * 3600 * 1 _000_000_000,
1495
+ kwargs[" days" ] * 24 * 3600 * 1 _000_000_000,
1496
+ kwargs[" hours" ] * 3600 * 1 _000_000_000,
1497
+ kwargs[" minutes" ] * 60 * 1 _000_000_000,
1498
+ kwargs[" seconds" ] * 1 _000_000_000,
1499
+ kwargs[" milliseconds" ] * 1 _000_000,
1500
+ kwargs[" microseconds" ] * 1 _000,
1501
+ kwargs[" nanoseconds" ],
1502
+ )),
1503
+ " ns" ,
1504
+ )
1505
+ else :
1506
+ if is_integer_object(value) or is_float_object(value):
1507
+ unit = parse_timedelta_unit(unit)
1520
1508
else :
1521
- value = parse_timedelta_string(value)
1522
- value = np.timedelta64(value)
1523
- elif PyDelta_Check(value):
1524
- value = convert_to_timedelta64(value, ' ns' )
1525
- elif is_timedelta64_object(value):
1526
- value = ensure_td64ns(value)
1527
- elif is_tick_object(value):
1528
- value = np.timedelta64(value.nanos, ' ns' )
1529
- elif is_integer_object(value) or is_float_object(value):
1530
- # unit=None is de-facto 'ns'
1531
- unit = parse_timedelta_unit(unit)
1509
+ unit = " ns"
1532
1510
value = convert_to_timedelta64(value, unit)
1533
- elif checknull_with_nat(value):
1534
- return NaT
1535
- else :
1536
- raise ValueError (
1537
- " Value must be Timedelta, string, integer, "
1538
- f" float, timedelta or convertible, not {type(value).__name__}"
1539
- )
1540
-
1541
- if is_timedelta64_object(value):
1542
- value = value.view(' i8' )
1543
-
1544
- # nat
1545
- if value == NPY_NAT:
1546
- return NaT
1547
-
1548
1511
except OverflowError as ex:
1549
1512
msg = f" outside allowed range [{TIMEDELTA_MIN_NS}ns, {TIMEDELTA_MAX_NS}ns]"
1550
1513
raise OutOfBoundsTimedelta(msg) from ex
1551
-
1552
- return _timedelta_from_value_and_reso(value, NPY_FR_ns)
1514
+ else :
1515
+ if is_td64nat(value):
1516
+ return NaT
1517
+ return _timedelta_from_value_and_reso(value.view(" i8" ), NPY_FR_ns)
1553
1518
1554
1519
def __setstate__ (self , state ):
1555
1520
if len (state) == 1 :
0 commit comments