Skip to content

Commit 03533df

Browse files
committed
Added check that timedelta can be represented by an integer number of nanoseconds
1 parent a57a0e4 commit 03533df

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

pandas/_libs/tslibs/timedeltas.pyx

+12-6
Original file line numberDiff line numberDiff line change
@@ -687,19 +687,25 @@ cdef timedelta_from_spec(object number, object frac, object unit):
687687
unit : a list of unit characters
688688
"""
689689
cdef:
690-
str n
690+
object ts
691+
int64_t result
691692

692693
unit = "".join(unit)
693694
if unit in ["M", "Y", "y"]:
694695
raise ValueError(
695-
"Units 'M', 'Y' and 'y' do not represent unambiguous timedelta "
696-
"values and are not supported."
696+
"Units 'M', 'Y' and 'y' do not represent unambiguous timedelta values and "
697+
"are not supported."
697698
)
698-
699699
unit = parse_timedelta_unit(unit)
700700

701-
n = "".join(number) + "." + "".join(frac)
702-
return cast_from_unit(float(n), unit)
701+
ts = float("".join(number) + "." + "".join(frac))
702+
result = cast_from_unit(ts, unit)
703+
704+
# Check that ts can be represented by an integer number of nanoseconds
705+
if result == 0 and ts > 0:
706+
raise ValueError("Resolution too high, maximum resolution is 1ns")
707+
708+
return result
703709

704710

705711
cpdef inline str parse_timedelta_unit(str unit):

pandas/tests/scalar/timedelta/test_constructors.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -407,13 +407,26 @@ def test_iso_constructor(fmt, exp):
407407
)
408408
def test_iso_constructor_raises_ambiguous_units(fmt):
409409
msg = (
410-
"Units 'M', 'Y' and 'y' do not represent unambiguous timedelta values "
411-
"and are not supported."
410+
"Units 'M', 'Y' and 'y' do not represent unambiguous timedelta values and are "
411+
"not supported."
412412
)
413413
with pytest.raises(ValueError, match=msg):
414414
Timedelta(fmt)
415415

416416

417+
@pytest.mark.parametrize(
418+
"fmt",
419+
[
420+
"P1DT0H0M0.0000000001S",
421+
"PT0.00000000001M",
422+
],
423+
)
424+
def test_iso_constructor_raises_resolution(fmt):
425+
msg = "Resolution too high, maximum resolution is 1ns"
426+
with pytest.raises(ValueError, match=msg):
427+
Timedelta(fmt)
428+
429+
417430
@pytest.mark.parametrize(
418431
"fmt",
419432
[
@@ -432,8 +445,6 @@ def test_iso_constructor_raises_ambiguous_units(fmt):
432445
"P1S",
433446
# Duplicate time separator
434447
"P1DTT1H",
435-
# Precision too high
436-
"P1DT0H0M0.0000000001S",
437448
# Only lowest order component may have be frational
438449
"P1DT2.5H3M",
439450
# Number start with in dot

0 commit comments

Comments
 (0)