Skip to content

Commit 577de1c

Browse files
authored
REF: de-duplicate code in libperiod (#33491)
1 parent 64de8f4 commit 577de1c

File tree

1 file changed

+39
-69
lines changed

1 file changed

+39
-69
lines changed

pandas/_libs/tslibs/period.pyx

+39-69
Original file line numberDiff line numberDiff line change
@@ -806,24 +806,22 @@ cdef int64_t get_period_ordinal(npy_datetimestruct *dts, int freq) nogil:
806806
return unix_date_to_week(unix_date, freq - FR_WK)
807807

808808

809-
cdef void get_date_info(int64_t ordinal, int freq,
810-
npy_datetimestruct *dts) nogil:
809+
cdef void get_date_info(int64_t ordinal, int freq, npy_datetimestruct *dts) nogil:
811810
cdef:
812-
int64_t unix_date
813-
double abstime
811+
int64_t unix_date, nanos
812+
npy_datetimestruct dts2
814813

815814
unix_date = get_unix_date(ordinal, freq)
816-
abstime = get_abs_time(freq, unix_date, ordinal)
817-
818-
while abstime < 0:
819-
abstime += 86400
820-
unix_date -= 1
815+
nanos = get_time_nanos(freq, unix_date, ordinal)
821816

822-
while abstime >= 86400:
823-
abstime -= 86400
824-
unix_date += 1
817+
pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, dts)
825818

826-
date_info_from_days_and_time(dts, unix_date, abstime)
819+
dt64_to_dtstruct(nanos, &dts2)
820+
dts.hour = dts2.hour
821+
dts.min = dts2.min
822+
dts.sec = dts2.sec
823+
dts.us = dts2.us
824+
dts.ps = dts2.ps
827825

828826

829827
cdef int64_t get_unix_date(int64_t period_ordinal, int freq) nogil:
@@ -855,74 +853,50 @@ cdef int64_t get_unix_date(int64_t period_ordinal, int freq) nogil:
855853

856854

857855
@cython.cdivision
858-
cdef void date_info_from_days_and_time(npy_datetimestruct *dts,
859-
int64_t unix_date,
860-
double abstime) nogil:
856+
cdef int64_t get_time_nanos(int freq, int64_t unix_date, int64_t ordinal) nogil:
861857
"""
862-
Set the instance's value using the given date and time.
858+
Find the number of nanoseconds after midnight on the given unix_date
859+
that the ordinal represents in the given frequency.
863860
864861
Parameters
865862
----------
866-
dts : npy_datetimestruct*
863+
freq : int
867864
unix_date : int64_t
868-
days elapsed since datetime(1970, 1, 1)
869-
abstime : double
870-
seconds elapsed since beginning of day described by unix_date
865+
ordinal : int64_t
871866
872-
Notes
873-
-----
874-
Updates dts inplace
867+
Returns
868+
-------
869+
int64_t
875870
"""
876871
cdef:
877-
int inttime
878-
int hour, minute
879-
double second, subsecond_fraction
880-
881-
# Bounds check
882-
# The calling function is responsible for ensuring that
883-
# abstime >= 0.0 and abstime <= 86400
884-
885-
# Calculate the date
886-
pandas_datetime_to_datetimestruct(unix_date, NPY_FR_D, dts)
872+
int64_t sub, factor
887873

888-
# Calculate the time
889-
inttime = <int>abstime
890-
hour = inttime / 3600
891-
minute = (inttime % 3600) / 60
892-
second = abstime - <double>(hour * 3600 + minute * 60)
874+
freq = get_freq_group(freq)
893875

894-
dts.hour = hour
895-
dts.min = minute
896-
dts.sec = <int>second
897-
898-
subsecond_fraction = second - dts.sec
899-
dts.us = int((subsecond_fraction) * 1e6)
900-
dts.ps = int(((subsecond_fraction) * 1e6 - dts.us) * 1e6)
876+
if freq <= FR_DAY:
877+
return 0
901878

879+
elif freq == FR_NS:
880+
factor = 1
902881

903-
@cython.cdivision
904-
cdef double get_abs_time(int freq, int64_t unix_date, int64_t ordinal) nogil:
905-
cdef:
906-
int freq_index, day_index, base_index
907-
int64_t per_day, start_ord
908-
double unit, result
882+
elif freq == FR_US:
883+
factor = 10**3
909884

910-
if freq <= FR_DAY:
911-
return 0
885+
elif freq == FR_MS:
886+
factor = 10**6
912887

913-
freq_index = freq // 1000
914-
day_index = FR_DAY // 1000
915-
base_index = FR_SEC // 1000
888+
elif freq == FR_SEC:
889+
factor = 10 **9
916890

917-
per_day = get_daytime_conversion_factor(day_index, freq_index)
918-
unit = get_daytime_conversion_factor(freq_index, base_index)
891+
elif freq == FR_MIN:
892+
factor = 10**9 * 60
919893

920-
if base_index < freq_index:
921-
unit = 1 / unit
894+
else:
895+
# We must have freq == FR_HR
896+
factor = 10**9 * 3600
922897

923-
start_ord = unix_date * per_day
924-
result = <double>(unit * (ordinal - start_ord))
925-
return result
898+
sub = ordinal - unix_date * 24 * 3600 * 10**9 / factor
899+
return sub * factor
926900

927901

928902
cdef int get_yq(int64_t ordinal, int freq, int *quarter, int *year):
@@ -1176,11 +1150,7 @@ cdef int64_t period_ordinal_to_dt64(int64_t ordinal, int freq) except? -1:
11761150
if ordinal == NPY_NAT:
11771151
return NPY_NAT
11781152

1179-
if freq == 11000:
1180-
# Microsecond, avoid get_date_info to prevent floating point errors
1181-
pandas_datetime_to_datetimestruct(ordinal, NPY_FR_us, &dts)
1182-
else:
1183-
get_date_info(ordinal, freq, &dts)
1153+
get_date_info(ordinal, freq, &dts)
11841154

11851155
check_dts_bounds(&dts)
11861156
return dtstruct_to_dt64(&dts)

0 commit comments

Comments
 (0)