Skip to content

Commit 0a516c1

Browse files
xcz011jbrockmendel
authored andcommitted
MAINT: port numpy#13188 for np_datetime simplification (#26516)
* MAINT: port numpy#13188 for np_datetime simplificaion Bring numpy changes about emulating the behavior of python's divmod to pandas. * cpplint fix * Add reference numpy change into comment * fix typo
1 parent 7e88819 commit 0a516c1

File tree

1 file changed

+81
-127
lines changed

1 file changed

+81
-127
lines changed

pandas/_libs/tslibs/src/datetime/np_datetime.c

+81-127
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,27 @@ npy_datetime npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT base,
498498
return ret;
499499
}
500500

501+
/*
502+
* Port numpy#13188 https://github.com/numpy/numpy/pull/13188/
503+
*
504+
* Computes the python `ret, d = divmod(d, unit)`.
505+
*
506+
* Note that GCC is smart enough at -O2 to eliminate the `if(*d < 0)` branch
507+
* for subsequent calls to this command - it is able to deduce that `*d >= 0`.
508+
*/
509+
npy_int64 extract_unit(npy_datetime *d, npy_datetime unit) {
510+
assert(unit > 0);
511+
npy_int64 div = *d / unit;
512+
npy_int64 mod = *d % unit;
513+
if (mod < 0) {
514+
mod += unit;
515+
div -= 1;
516+
}
517+
assert(mod >= 0);
518+
*d = mod;
519+
return div;
520+
}
521+
501522
/*
502523
* Converts a datetime based on the given metadata into a datetimestruct
503524
*/
@@ -522,13 +543,8 @@ void pandas_datetime_to_datetimestruct(npy_datetime dt,
522543
break;
523544

524545
case NPY_FR_M:
525-
if (dt >= 0) {
526-
out->year = 1970 + dt / 12;
527-
out->month = dt % 12 + 1;
528-
} else {
529-
out->year = 1969 + (dt + 1) / 12;
530-
out->month = 12 + (dt + 1) % 12;
531-
}
546+
out->year = 1970 + extract_unit(&dt, 12);
547+
out->month = dt + 1;
532548
break;
533549

534550
case NPY_FR_W:
@@ -543,167 +559,105 @@ void pandas_datetime_to_datetimestruct(npy_datetime dt,
543559
case NPY_FR_h:
544560
perday = 24LL;
545561

546-
if (dt >= 0) {
547-
set_datetimestruct_days(dt / perday, out);
548-
dt = dt % perday;
549-
} else {
550-
set_datetimestruct_days(
551-
dt / perday - (dt % perday == 0 ? 0 : 1), out);
552-
dt = (perday - 1) + (dt + 1) % perday;
553-
}
562+
set_datetimestruct_days(extract_unit(&dt, perday), out);
554563
out->hour = dt;
555564
break;
556565

557566
case NPY_FR_m:
558567
perday = 24LL * 60;
559568

560-
if (dt >= 0) {
561-
set_datetimestruct_days(dt / perday, out);
562-
dt = dt % perday;
563-
} else {
564-
set_datetimestruct_days(
565-
dt / perday - (dt % perday == 0 ? 0 : 1), out);
566-
dt = (perday - 1) + (dt + 1) % perday;
567-
}
568-
out->hour = dt / 60;
569-
out->min = dt % 60;
569+
set_datetimestruct_days(extract_unit(&dt, perday), out);
570+
out->hour = (int)extract_unit(&dt, 60);
571+
out->min = (int)dt;
570572
break;
571573

572574
case NPY_FR_s:
573575
perday = 24LL * 60 * 60;
574576

575-
if (dt >= 0) {
576-
set_datetimestruct_days(dt / perday, out);
577-
dt = dt % perday;
578-
} else {
579-
set_datetimestruct_days(
580-
dt / perday - (dt % perday == 0 ? 0 : 1), out);
581-
dt = (perday - 1) + (dt + 1) % perday;
582-
}
583-
out->hour = dt / (60 * 60);
584-
out->min = (dt / 60) % 60;
585-
out->sec = dt % 60;
577+
set_datetimestruct_days(extract_unit(&dt, perday), out);
578+
out->hour = (int)extract_unit(&dt, 60 * 60);
579+
out->min = (int)extract_unit(&dt, 60);
580+
out->sec = (int)dt;
586581
break;
587582

588583
case NPY_FR_ms:
589584
perday = 24LL * 60 * 60 * 1000;
590585

591-
if (dt >= 0) {
592-
set_datetimestruct_days(dt / perday, out);
593-
dt = dt % perday;
594-
} else {
595-
set_datetimestruct_days(
596-
dt / perday - (dt % perday == 0 ? 0 : 1), out);
597-
dt = (perday - 1) + (dt + 1) % perday;
598-
}
599-
out->hour = dt / (60 * 60 * 1000LL);
600-
out->min = (dt / (60 * 1000LL)) % 60;
601-
out->sec = (dt / 1000LL) % 60;
602-
out->us = (dt % 1000LL) * 1000;
586+
set_datetimestruct_days(extract_unit(&dt, perday), out);
587+
out->hour = (int)extract_unit(&dt, 1000LL * 60 * 60);
588+
out->min = (int)extract_unit(&dt, 1000LL * 60);
589+
out->sec = (int)extract_unit(&dt, 1000LL);
590+
out->us = (int)(dt * 1000);
603591
break;
604592

605593
case NPY_FR_us:
606594
perday = 24LL * 60LL * 60LL * 1000LL * 1000LL;
607595

608-
if (dt >= 0) {
609-
set_datetimestruct_days(dt / perday, out);
610-
dt = dt % perday;
611-
} else {
612-
set_datetimestruct_days(
613-
dt / perday - (dt % perday == 0 ? 0 : 1), out);
614-
dt = (perday - 1) + (dt + 1) % perday;
615-
}
616-
out->hour = dt / (60 * 60 * 1000000LL);
617-
out->min = (dt / (60 * 1000000LL)) % 60;
618-
out->sec = (dt / 1000000LL) % 60;
619-
out->us = dt % 1000000LL;
596+
set_datetimestruct_days(extract_unit(&dt, perday), out);
597+
out->hour = (int)extract_unit(&dt, 1000LL * 1000 * 60 * 60);
598+
out->min = (int)extract_unit(&dt, 1000LL * 1000 * 60);
599+
out->sec = (int)extract_unit(&dt, 1000LL * 1000);
600+
out->us = (int)dt;
620601
break;
621602

622603
case NPY_FR_ns:
623604
perday = 24LL * 60LL * 60LL * 1000LL * 1000LL * 1000LL;
624605

625-
if (dt >= 0) {
626-
set_datetimestruct_days(dt / perday, out);
627-
dt = dt % perday;
628-
} else {
629-
set_datetimestruct_days(
630-
dt / perday - (dt % perday == 0 ? 0 : 1), out);
631-
dt = (perday - 1) + (dt + 1) % perday;
632-
}
633-
out->hour = dt / (60 * 60 * 1000000000LL);
634-
out->min = (dt / (60 * 1000000000LL)) % 60;
635-
out->sec = (dt / 1000000000LL) % 60;
636-
out->us = (dt / 1000LL) % 1000000LL;
637-
out->ps = (dt % 1000LL) * 1000;
606+
set_datetimestruct_days(extract_unit(&dt, perday), out);
607+
out->hour = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 60 * 60);
608+
out->min = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 60);
609+
out->sec = (int)extract_unit(&dt, 1000LL * 1000 * 1000);
610+
out->us = (int)extract_unit(&dt, 1000LL);
611+
out->ps = (int)(dt * 1000);
638612
break;
639613

640614
case NPY_FR_ps:
641615
perday = 24LL * 60 * 60 * 1000 * 1000 * 1000 * 1000;
642616

643-
if (dt >= 0) {
644-
set_datetimestruct_days(dt / perday, out);
645-
dt = dt % perday;
646-
} else {
647-
set_datetimestruct_days(
648-
dt / perday - (dt % perday == 0 ? 0 : 1), out);
649-
dt = (perday - 1) + (dt + 1) % perday;
650-
}
651-
out->hour = dt / (60 * 60 * 1000000000000LL);
652-
out->min = (dt / (60 * 1000000000000LL)) % 60;
653-
out->sec = (dt / 1000000000000LL) % 60;
654-
out->us = (dt / 1000000LL) % 1000000LL;
655-
out->ps = dt % 1000000LL;
617+
set_datetimestruct_days(extract_unit(&dt, perday), out);
618+
out->hour = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 60 * 60);
619+
out->min = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 60);
620+
out->sec = (int)extract_unit(&dt, 1000LL * 1000 * 1000);
621+
out->us = (int)extract_unit(&dt, 1000LL);
622+
out->ps = (int)(dt * 1000);
656623
break;
657624

658625
case NPY_FR_fs:
659626
/* entire range is only +- 2.6 hours */
660-
if (dt >= 0) {
661-
out->hour = dt / (60 * 60 * 1000000000000000LL);
662-
out->min = (dt / (60 * 1000000000000000LL)) % 60;
663-
out->sec = (dt / 1000000000000000LL) % 60;
664-
out->us = (dt / 1000000000LL) % 1000000LL;
665-
out->ps = (dt / 1000LL) % 1000000LL;
666-
out->as = (dt % 1000LL) * 1000;
667-
} else {
668-
npy_datetime minutes;
669-
670-
minutes = dt / (60 * 1000000000000000LL);
671-
dt = dt % (60 * 1000000000000000LL);
672-
if (dt < 0) {
673-
dt += (60 * 1000000000000000LL);
674-
--minutes;
675-
}
676-
/* Offset the negative minutes */
677-
add_minutes_to_datetimestruct(out, minutes);
678-
out->sec = (dt / 1000000000000000LL) % 60;
679-
out->us = (dt / 1000000000LL) % 1000000LL;
680-
out->ps = (dt / 1000LL) % 1000000LL;
681-
out->as = (dt % 1000LL) * 1000;
627+
out->hour = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 1000 *
628+
1000 * 60 * 60);
629+
if (out->hour < 0) {
630+
out->year = 1969;
631+
out->month = 12;
632+
out->day = 31;
633+
out->hour += 24;
634+
assert(out->hour >= 0);
682635
}
636+
out->min = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 1000 *
637+
1000 * 60);
638+
out->sec = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 1000 *
639+
1000);
640+
out->us = (int)extract_unit(&dt, 1000LL * 1000 * 1000);
641+
out->ps = (int)extract_unit(&dt, 1000LL);
642+
out->as = (int)(dt * 1000);
683643
break;
684644

685645
case NPY_FR_as:
686646
/* entire range is only +- 9.2 seconds */
687-
if (dt >= 0) {
688-
out->sec = (dt / 1000000000000000000LL) % 60;
689-
out->us = (dt / 1000000000000LL) % 1000000LL;
690-
out->ps = (dt / 1000000LL) % 1000000LL;
691-
out->as = dt % 1000000LL;
692-
} else {
693-
npy_datetime seconds;
694-
695-
seconds = dt / 1000000000000000000LL;
696-
dt = dt % 1000000000000000000LL;
697-
if (dt < 0) {
698-
dt += 1000000000000000000LL;
699-
--seconds;
700-
}
701-
/* Offset the negative seconds */
702-
add_seconds_to_datetimestruct(out, seconds);
703-
out->us = (dt / 1000000000000LL) % 1000000LL;
704-
out->ps = (dt / 1000000LL) % 1000000LL;
705-
out->as = dt % 1000000LL;
647+
out->sec = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 1000 *
648+
1000 * 1000);
649+
if (out->sec < 0) {
650+
out->year = 1969;
651+
out->month = 12;
652+
out->day = 31;
653+
out->hour = 23;
654+
out->min = 59;
655+
out->sec += 60;
656+
assert(out->sec >= 0);
706657
}
658+
out->us = (int)extract_unit(&dt, 1000LL * 1000 * 1000 * 1000);
659+
out->ps = (int)extract_unit(&dt, 1000LL * 1000);
660+
out->as = (int)dt;
707661
break;
708662

709663
default:

0 commit comments

Comments
 (0)