1
- cimport cython
2
1
from cpython.datetime cimport (
3
2
PyDateTime_CheckExact,
4
3
PyDateTime_DATE_GET_HOUR,
@@ -18,6 +17,7 @@ from cpython.object cimport (
18
17
Py_LT,
19
18
Py_NE,
20
19
)
20
+ from libc.stdint cimport INT64_MAX
21
21
22
22
import_datetime()
23
23
PandasDateTime_IMPORT
@@ -545,14 +545,14 @@ cdef ndarray astype_round_check(
545
545
return iresult
546
546
547
547
548
- @ cython.overflowcheck (True )
549
548
cdef int64_t get_conversion_factor(
550
549
NPY_DATETIMEUNIT from_unit,
551
550
NPY_DATETIMEUNIT to_unit
552
551
) except ? - 1 :
553
552
"""
554
553
Find the factor by which we need to multiply to convert from from_unit to to_unit.
555
554
"""
555
+ cdef int64_t value, overflow_limit, factor
556
556
if (
557
557
from_unit == NPY_DATETIMEUNIT.NPY_FR_GENERIC
558
558
or to_unit == NPY_DATETIMEUNIT.NPY_FR_GENERIC
@@ -565,28 +565,44 @@ cdef int64_t get_conversion_factor(
565
565
return 1
566
566
567
567
if from_unit == NPY_DATETIMEUNIT.NPY_FR_W:
568
- return 7 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_D, to_unit)
568
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_D, to_unit)
569
+ factor = 7
569
570
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_D:
570
- return 24 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_h, to_unit)
571
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_h, to_unit)
572
+ factor = 24
571
573
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_h:
572
- return 60 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_m, to_unit)
574
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_m, to_unit)
575
+ factor = 60
573
576
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_m:
574
- return 60 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_s, to_unit)
577
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_s, to_unit)
578
+ factor = 60
575
579
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_s:
576
- return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ms, to_unit)
580
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ms, to_unit)
581
+ factor = 1000
577
582
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ms:
578
- return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_us, to_unit)
583
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_us, to_unit)
584
+ factor = 1000
579
585
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_us:
580
- return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ns, to_unit)
586
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ns, to_unit)
587
+ factor = 1000
581
588
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ns:
582
- return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ps, to_unit)
589
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_ps, to_unit)
590
+ factor = 1000
583
591
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_ps:
584
- return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_fs, to_unit)
592
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_fs, to_unit)
593
+ factor = 1000
585
594
elif from_unit == NPY_DATETIMEUNIT.NPY_FR_fs:
586
- return 1000 * get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_as, to_unit)
595
+ value = get_conversion_factor(NPY_DATETIMEUNIT.NPY_FR_as, to_unit)
596
+ factor = 1000
587
597
else :
588
598
raise ValueError (" Converting from M or Y units is not supported." )
589
599
600
+ overflow_limit = INT64_MAX // factor
601
+ if value > overflow_limit or value < - overflow_limit:
602
+ raise OverflowError (" result would overflow" )
603
+
604
+ return factor * value
605
+
590
606
591
607
cdef int64_t convert_reso(
592
608
int64_t value,
@@ -595,7 +611,7 @@ cdef int64_t convert_reso(
595
611
bint round_ok,
596
612
) except ? - 1 :
597
613
cdef:
598
- int64_t res_value, mult, div, mod
614
+ int64_t res_value, mult, div, mod, overflow_limit
599
615
600
616
if from_reso == to_reso:
601
617
return value
@@ -624,9 +640,12 @@ cdef int64_t convert_reso(
624
640
else :
625
641
# e.g. ns -> us, risk of overflow, but no risk of lossy rounding
626
642
mult = get_conversion_factor(from_reso, to_reso)
627
- with cython.overflowcheck(True ):
643
+ overflow_limit = INT64_MAX // mult
644
+ if value > overflow_limit or value < - overflow_limit:
628
645
# Note: caller is responsible for re-raising as OutOfBoundsTimedelta
629
- res_value = value * mult
646
+ raise OverflowError (" result would overflow" )
647
+
648
+ res_value = value * mult
630
649
631
650
return res_value
632
651
0 commit comments