26
26
#include "_datetime.h"
27
27
#include "datetime_strings.h"
28
28
29
+ /*
30
+ * Computes the python `ret, d = divmod(d, unit)`.
31
+ *
32
+ * Note that GCC is smart enough at -O2 to eliminate the `if(*d < 0)` branch
33
+ * for subsequent calls to this command - it is able to deduce that `*d >= 0`.
34
+ */
35
+ static inline
36
+ npy_int64 extract_unit_64 (npy_int64 * d , npy_int64 unit ) {
37
+ assert (unit > 0 );
38
+ npy_int64 div = * d / unit ;
39
+ npy_int64 mod = * d % unit ;
40
+ if (mod < 0 ) {
41
+ mod += unit ;
42
+ div -= 1 ;
43
+ }
44
+ assert (mod >= 0 );
45
+ * d = mod ;
46
+ return div ;
47
+ }
48
+
49
+ static inline
50
+ npy_int32 extract_unit_32 (npy_int32 * d , npy_int32 unit ) {
51
+ assert (unit > 0 );
52
+ npy_int32 div = * d / unit ;
53
+ npy_int32 mod = * d % unit ;
54
+ if (mod < 0 ) {
55
+ mod += unit ;
56
+ div -= 1 ;
57
+ }
58
+ assert (mod >= 0 );
59
+ * d = mod ;
60
+ return div ;
61
+ }
62
+
29
63
/*
30
64
* Imports the PyDateTime functions so we can create these objects.
31
65
* This is called during module initialization
@@ -160,17 +194,7 @@ days_to_yearsdays(npy_int64 *days_)
160
194
npy_int64 year ;
161
195
162
196
/* Break down the 400 year cycle to get the year and day within the year */
163
- if (days >= 0 ) {
164
- year = 400 * (days / days_per_400years );
165
- days = days % days_per_400years ;
166
- }
167
- else {
168
- year = 400 * ((days - (days_per_400years - 1 )) / days_per_400years );
169
- days = days % days_per_400years ;
170
- if (days < 0 ) {
171
- days += days_per_400years ;
172
- }
173
- }
197
+ year = 400 * extract_unit_64 (& days , days_per_400years );
174
198
175
199
/* Work out the year/day within the 400 year cycle */
176
200
if (days >= 366 ) {
@@ -410,26 +434,6 @@ PyArray_TimedeltaStructToTimedelta(
410
434
return -1 ;
411
435
}
412
436
413
- /*
414
- * Computes the python `ret, d = divmod(d, unit)`.
415
- *
416
- * Note that GCC is smart enough at -O2 to eliminate the `if(*d < 0)` branch
417
- * for subsequent calls to this command - it is able to deduce that `*d >= 0`.
418
- */
419
- static inline
420
- npy_int64 extract_unit (npy_datetime * d , npy_datetime unit ) {
421
- assert (unit > 0 );
422
- npy_int64 div = * d / unit ;
423
- npy_int64 mod = * d % unit ;
424
- if (mod < 0 ) {
425
- mod += unit ;
426
- div -= 1 ;
427
- }
428
- assert (mod >= 0 );
429
- * d = mod ;
430
- return div ;
431
- }
432
-
433
437
/*
434
438
* Converts a datetime based on the given metadata into a datetimestruct
435
439
*/
@@ -438,7 +442,7 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
438
442
npy_datetime dt ,
439
443
npy_datetimestruct * out )
440
444
{
441
- npy_int64 perday ;
445
+ npy_int64 days ;
442
446
443
447
/* Initialize the output to all zeros */
444
448
memset (out , 0 , sizeof (npy_datetimestruct ));
@@ -473,7 +477,7 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
473
477
break ;
474
478
475
479
case NPY_FR_M :
476
- out -> year = 1970 + extract_unit (& dt , 12 );
480
+ out -> year = 1970 + extract_unit_64 (& dt , 12 );
477
481
out -> month = dt + 1 ;
478
482
break ;
479
483
@@ -487,90 +491,84 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
487
491
break ;
488
492
489
493
case NPY_FR_h :
490
- perday = 24LL ;
491
-
492
- set_datetimestruct_days (extract_unit (& dt , perday ), out );
494
+ days = extract_unit_64 (& dt , 24LL );
495
+ set_datetimestruct_days (days , out );
493
496
out -> hour = (int )dt ;
494
497
break ;
495
498
496
499
case NPY_FR_m :
497
- perday = 24LL * 60 ;
498
-
499
- set_datetimestruct_days (extract_unit (& dt , perday ), out );
500
- out -> hour = (int )extract_unit (& dt , 60 );
501
- out -> min = (int )dt ;
500
+ days = extract_unit_64 (& dt , 60LL * 24 );
501
+ set_datetimestruct_days (days , out );
502
+ out -> hour = (int )extract_unit_64 (& dt , 60LL );
503
+ out -> min = (int )dt ;
502
504
break ;
503
505
504
506
case NPY_FR_s :
505
- perday = 24LL * 60 * 60 ;
506
-
507
- set_datetimestruct_days (extract_unit (& dt , perday ), out );
508
- out -> hour = (int )extract_unit (& dt , 60 * 60 );
509
- out -> min = (int )extract_unit (& dt , 60 );
507
+ days = extract_unit_64 (& dt , 60LL * 60 * 24 );
508
+ set_datetimestruct_days (days , out );
509
+ out -> hour = (int )extract_unit_64 (& dt , 60LL * 60 );
510
+ out -> min = (int )extract_unit_64 (& dt , 60LL );
510
511
out -> sec = (int )dt ;
511
512
break ;
512
513
513
514
case NPY_FR_ms :
514
- perday = 24LL * 60 * 60 * 1000 ;
515
-
516
- set_datetimestruct_days (extract_unit (& dt , perday ), out );
517
- out -> hour = (int )extract_unit (& dt , 1000LL * 60 * 60 );
518
- out -> min = (int )extract_unit (& dt , 1000LL * 60 );
519
- out -> sec = (int )extract_unit (& dt , 1000LL );
515
+ days = extract_unit_64 (& dt , 1000LL * 60 * 60 * 24 );
516
+ set_datetimestruct_days (days , out );
517
+ out -> hour = (int )extract_unit_64 (& dt , 1000LL * 60 * 60 );
518
+ out -> min = (int )extract_unit_64 (& dt , 1000LL * 60 );
519
+ out -> sec = (int )extract_unit_64 (& dt , 1000LL );
520
520
out -> us = (int )(dt * 1000 );
521
521
break ;
522
522
523
523
case NPY_FR_us :
524
- perday = 24LL * 60LL * 60LL * 1000LL * 1000LL ;
525
- set_datetimestruct_days (extract_unit ( & dt , perday ) , out );
526
- out -> hour = (int )extract_unit (& dt , 1000LL * 1000 * 60 * 60 );
527
- out -> min = (int )extract_unit (& dt , 1000LL * 1000 * 60 );
528
- out -> sec = (int )extract_unit (& dt , 1000LL * 1000 );
524
+ days = extract_unit_64 ( & dt , 1000LL * 1000 * 60 * 60 * 24 ) ;
525
+ set_datetimestruct_days (days , out );
526
+ out -> hour = (int )extract_unit_64 (& dt , 1000LL * 1000 * 60 * 60 );
527
+ out -> min = (int )extract_unit_64 (& dt , 1000LL * 1000 * 60 );
528
+ out -> sec = (int )extract_unit_64 (& dt , 1000LL * 1000 );
529
529
out -> us = (int )dt ;
530
530
break ;
531
531
532
532
case NPY_FR_ns :
533
- perday = 24LL * 60LL * 60LL * 1000LL * 1000LL * 1000LL ;
534
-
535
- set_datetimestruct_days (extract_unit (& dt , perday ), out );
536
- out -> hour = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 60 * 60 );
537
- out -> min = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 60 );
538
- out -> sec = (int )extract_unit (& dt , 1000LL * 1000 * 1000 );
539
- out -> us = (int )extract_unit (& dt , 1000LL );
533
+ days = extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 60 * 60 * 24 );
534
+ set_datetimestruct_days (days , out );
535
+ out -> hour = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 60 * 60 );
536
+ out -> min = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 60 );
537
+ out -> sec = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 );
538
+ out -> us = (int )extract_unit_64 (& dt , 1000LL );
540
539
out -> ps = (int )(dt * 1000 );
541
540
break ;
542
541
543
542
case NPY_FR_ps :
544
- perday = 24LL * 60 * 60 * 1000 * 1000 * 1000 * 1000 ;
545
-
546
- set_datetimestruct_days (extract_unit (& dt , perday ), out );
547
- out -> hour = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 1000 * 60 * 60 );
548
- out -> min = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 1000 * 60 );
549
- out -> sec = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 1000 );
550
- out -> us = (int )extract_unit (& dt , 1000LL * 1000 );
543
+ days = extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 * 60 * 60 * 24 );
544
+ set_datetimestruct_days (days , out );
545
+ out -> hour = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 * 60 * 60 );
546
+ out -> min = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 * 60 );
547
+ out -> sec = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 );
548
+ out -> us = (int )extract_unit_64 (& dt , 1000LL * 1000 );
551
549
out -> ps = (int )(dt );
552
550
break ;
553
551
554
552
case NPY_FR_fs :
555
553
/* entire range is only +- 2.6 hours */
556
- out -> hour = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 1000 * 1000 * 60 * 60 );
554
+ out -> hour = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 * 1000 * 60 * 60 );
557
555
if (out -> hour < 0 ) {
558
556
out -> year = 1969 ;
559
557
out -> month = 12 ;
560
558
out -> day = 31 ;
561
559
out -> hour += 24 ;
562
560
assert (out -> hour >= 0 );
563
561
}
564
- out -> min = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 1000 * 1000 * 60 );
565
- out -> sec = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 1000 * 1000 );
566
- out -> us = (int )extract_unit (& dt , 1000LL * 1000 * 1000 );
567
- out -> ps = (int )extract_unit (& dt , 1000LL );
562
+ out -> min = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 * 1000 * 60 );
563
+ out -> sec = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 * 1000 );
564
+ out -> us = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 );
565
+ out -> ps = (int )extract_unit_64 (& dt , 1000LL );
568
566
out -> as = (int )(dt * 1000 );
569
567
break ;
570
568
571
569
case NPY_FR_as :
572
570
/* entire range is only +- 9.2 seconds */
573
- out -> sec = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 1000 * 1000 * 1000 );
571
+ out -> sec = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 * 1000 * 1000 );
574
572
if (out -> sec < 0 ) {
575
573
out -> year = 1969 ;
576
574
out -> month = 12 ;
@@ -580,8 +578,8 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
580
578
out -> sec += 60 ;
581
579
assert (out -> sec >= 0 );
582
580
}
583
- out -> us = (int )extract_unit (& dt , 1000LL * 1000 * 1000 * 1000 );
584
- out -> ps = (int )extract_unit (& dt , 1000LL * 1000 );
581
+ out -> us = (int )extract_unit_64 (& dt , 1000LL * 1000 * 1000 * 1000 );
582
+ out -> ps = (int )extract_unit_64 (& dt , 1000LL * 1000 );
585
583
out -> as = (int )dt ;
586
584
break ;
587
585
@@ -2017,20 +2015,8 @@ add_seconds_to_datetimestruct(npy_datetimestruct *dts, int seconds)
2017
2015
int minutes ;
2018
2016
2019
2017
dts -> sec += seconds ;
2020
- if (dts -> sec < 0 ) {
2021
- minutes = dts -> sec / 60 ;
2022
- dts -> sec = dts -> sec % 60 ;
2023
- if (dts -> sec < 0 ) {
2024
- -- minutes ;
2025
- dts -> sec += 60 ;
2026
- }
2027
- add_minutes_to_datetimestruct (dts , minutes );
2028
- }
2029
- else if (dts -> sec >= 60 ) {
2030
- minutes = dts -> sec / 60 ;
2031
- dts -> sec = dts -> sec % 60 ;
2032
- add_minutes_to_datetimestruct (dts , minutes );
2033
- }
2018
+ minutes = extract_unit_32 (& dts -> sec , 60 );
2019
+ add_minutes_to_datetimestruct (dts , minutes );
2034
2020
}
2035
2021
2036
2022
/*
@@ -2042,28 +2028,13 @@ add_minutes_to_datetimestruct(npy_datetimestruct *dts, int minutes)
2042
2028
{
2043
2029
int isleap ;
2044
2030
2045
- /* MINUTES */
2046
2031
dts -> min += minutes ;
2047
- while (dts -> min < 0 ) {
2048
- dts -> min += 60 ;
2049
- dts -> hour -- ;
2050
- }
2051
- while (dts -> min >= 60 ) {
2052
- dts -> min -= 60 ;
2053
- dts -> hour ++ ;
2054
- }
2055
2032
2056
- /* HOURS */
2057
- while (dts -> hour < 0 ) {
2058
- dts -> hour += 24 ;
2059
- dts -> day -- ;
2060
- }
2061
- while (dts -> hour >= 24 ) {
2062
- dts -> hour -= 24 ;
2063
- dts -> day ++ ;
2064
- }
2033
+ /* propagate invalid minutes into hour and day changes */
2034
+ dts -> hour += extract_unit_32 (& dts -> min , 60 );
2035
+ dts -> day += extract_unit_32 (& dts -> hour , 24 );
2065
2036
2066
- /* DAYS */
2037
+ /* propagate invalid days into month and year changes */
2067
2038
if (dts -> day < 1 ) {
2068
2039
dts -> month -- ;
2069
2040
if (dts -> month < 1 ) {
@@ -2890,7 +2861,6 @@ convert_datetime_to_pyobject(npy_datetime dt, PyArray_DatetimeMetaData *meta)
2890
2861
NPY_NO_EXPORT PyObject *
2891
2862
convert_timedelta_to_pyobject (npy_timedelta td , PyArray_DatetimeMetaData * meta )
2892
2863
{
2893
- PyObject * ret = NULL ;
2894
2864
npy_timedelta value ;
2895
2865
int days = 0 , seconds = 0 , useconds = 0 ;
2896
2866
@@ -2920,54 +2890,47 @@ convert_timedelta_to_pyobject(npy_timedelta td, PyArray_DatetimeMetaData *meta)
2920
2890
/* Convert to days/seconds/useconds */
2921
2891
switch (meta -> base ) {
2922
2892
case NPY_FR_W :
2923
- value *= 7 ;
2893
+ days = value * 7 ;
2924
2894
break ;
2925
2895
case NPY_FR_D :
2896
+ days = value ;
2926
2897
break ;
2927
2898
case NPY_FR_h :
2928
- seconds = ( int )(( value % 24 ) * ( 60 * 60 ) );
2929
- value = value / 24 ;
2899
+ days = extract_unit_64 ( & value , 24ULL );
2900
+ seconds = value * 60 * 60 ;
2930
2901
break ;
2931
2902
case NPY_FR_m :
2932
- seconds = ( int )( value % ( 24 * 60 )) * 60 ;
2933
- value = value / ( 24 * 60 ) ;
2903
+ days = extract_unit_64 ( & value , 60ULL * 24 ) ;
2904
+ seconds = value * 60 ;
2934
2905
break ;
2935
2906
case NPY_FR_s :
2936
- seconds = ( int )( value % ( 24 * 60 * 60 ) );
2937
- value = value / ( 24 * 60 * 60 ) ;
2907
+ days = extract_unit_64 ( & value , 60ULL * 60 * 24 );
2908
+ seconds = value ;
2938
2909
break ;
2939
2910
case NPY_FR_ms :
2940
- useconds = (int )(value % 1000 ) * 1000 ;
2941
- value = value / 1000 ;
2942
- seconds = (int )(value % (24 * 60 * 60 ));
2943
- value = value / (24 * 60 * 60 );
2911
+ days = extract_unit_64 (& value , 1000ULL * 60 * 60 * 24 );
2912
+ seconds = extract_unit_64 (& value , 1000ULL );
2913
+ useconds = value * 1000 ;
2944
2914
break ;
2945
2915
case NPY_FR_us :
2946
- useconds = (int )(value % (1000 * 1000 ));
2947
- value = value / (1000 * 1000 );
2948
- seconds = (int )(value % (24 * 60 * 60 ));
2949
- value = value / (24 * 60 * 60 );
2916
+ days = extract_unit_64 (& value , 1000ULL * 1000 * 60 * 60 * 24 );
2917
+ seconds = extract_unit_64 (& value , 1000ULL * 1000 );
2918
+ useconds = value ;
2950
2919
break ;
2951
2920
default :
2921
+ // unreachable, handled by the `if` above
2922
+ assert (NPY_FALSE );
2952
2923
break ;
2953
2924
}
2954
2925
/*
2955
- * 'value' represents days, and seconds/useconds are filled.
2956
- *
2957
2926
* If it would overflow the datetime.timedelta days, return a raw int
2958
2927
*/
2959
- if (value < -999999999 || value > 999999999 ) {
2928
+ if (days < -999999999 || days > 999999999 ) {
2960
2929
return PyLong_FromLongLong (td );
2961
2930
}
2962
2931
else {
2963
- days = (int )value ;
2964
- ret = PyDelta_FromDSU (days , seconds , useconds );
2965
- if (ret == NULL ) {
2966
- return NULL ;
2967
- }
2932
+ return PyDelta_FromDSU (days , seconds , useconds );
2968
2933
}
2969
-
2970
- return ret ;
2971
2934
}
2972
2935
2973
2936
/*
0 commit comments