Skip to content

Commit 8532faa

Browse files
authored
BUG: Fix nanosecond timedeltas (#45108)
1 parent 13147f3 commit 8532faa

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

doc/source/whatsnew/v1.4.0.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,8 @@ Timedelta
757757
^^^^^^^^^
758758
- Bug in division of all-``NaT`` :class:`TimeDeltaIndex`, :class:`Series` or :class:`DataFrame` column with object-dtype arraylike of numbers failing to infer the result as timedelta64-dtype (:issue:`39750`)
759759
- Bug in floor division of ``timedelta64[ns]`` data with a scalar returning garbage values (:issue:`44466`)
760+
- Bug in :class:`Timedelta` now properly taking into account any nanoseconds contribution of any kwarg (:issue:`43764`)
761+
-
760762

761763
Timezones
762764
^^^^^^^^^

pandas/_libs/tslibs/timedeltas.pyx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ cpdef int64_t delta_to_nanoseconds(delta) except? -1:
180180
if PyDelta_Check(delta):
181181
try:
182182
return (
183-
delta.days * 24 * 60 * 60 * 1_000_000
183+
delta.days * 24 * 3600 * 1_000_000
184184
+ delta.seconds * 1_000_000
185185
+ delta.microseconds
186186
) * 1000
@@ -1257,6 +1257,9 @@ class Timedelta(_Timedelta):
12571257
truncated to nanoseconds.
12581258
"""
12591259

1260+
_req_any_kwargs_new = {"weeks", "days", "hours", "minutes", "seconds",
1261+
"milliseconds", "microseconds", "nanoseconds"}
1262+
12601263
def __new__(cls, object value=_no_input, unit=None, **kwargs):
12611264
cdef _Timedelta td_base
12621265

@@ -1267,19 +1270,35 @@ class Timedelta(_Timedelta):
12671270
"(days,seconds....)")
12681271

12691272
kwargs = {key: _to_py_int_float(kwargs[key]) for key in kwargs}
1270-
1271-
nano = convert_to_timedelta64(kwargs.pop('nanoseconds', 0), 'ns')
1272-
try:
1273-
value = nano + convert_to_timedelta64(timedelta(**kwargs),
1274-
'ns')
1275-
except TypeError as e:
1273+
if not cls._req_any_kwargs_new.intersection(kwargs):
12761274
raise ValueError(
12771275
"cannot construct a Timedelta from the passed arguments, "
12781276
"allowed keywords are "
12791277
"[weeks, days, hours, minutes, seconds, "
12801278
"milliseconds, microseconds, nanoseconds]"
12811279
)
12821280

1281+
# GH43764, convert any input to nanoseconds first and then
1282+
# create the timestamp. This ensures that any potential
1283+
# nanosecond contributions from kwargs parsed as floats
1284+
# are taken into consideration.
1285+
seconds = int((
1286+
(
1287+
(kwargs.get('days', 0) + kwargs.get('weeks', 0) * 7) * 24
1288+
+ kwargs.get('hours', 0)
1289+
) * 3600
1290+
+ kwargs.get('minutes', 0) * 60
1291+
+ kwargs.get('seconds', 0)
1292+
) * 1_000_000_000
1293+
)
1294+
1295+
value = np.timedelta64(
1296+
int(kwargs.get('nanoseconds', 0))
1297+
+ int(kwargs.get('microseconds', 0) * 1_000)
1298+
+ int(kwargs.get('milliseconds', 0) * 1_000_000)
1299+
+ seconds
1300+
)
1301+
12831302
if unit in {'Y', 'y', 'M'}:
12841303
raise ValueError(
12851304
"Units 'M', 'Y', and 'y' are no longer supported, as they do not "

pandas/tests/tslibs/test_timedeltas.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
(np.timedelta64(14, "D"), 14 * 24 * 3600 * 1e9),
1616
(Timedelta(minutes=-7), -7 * 60 * 1e9),
1717
(Timedelta(minutes=-7).to_pytimedelta(), -7 * 60 * 1e9),
18+
(Timedelta(seconds=1234e-9), 1234), # GH43764, GH40946
19+
(
20+
Timedelta(seconds=1e-9, milliseconds=1e-5, microseconds=1e-1),
21+
111,
22+
), # GH43764
23+
(
24+
Timedelta(days=1, seconds=1e-9, milliseconds=1e-5, microseconds=1e-1),
25+
24 * 3600e9 + 111,
26+
), # GH43764
1827
(offsets.Nano(125), 125),
1928
(1, 1),
2029
(np.int64(2), 2),

0 commit comments

Comments
 (0)