@@ -357,18 +357,15 @@ cdef int64_t asfreq_QtoDT(int64_t ordinal, asfreq_info *af_info) nogil:
357357 return upsample_daytime(unix_date, af_info)
358358
359359
360- cdef void MtoD_ym(int64_t ordinal, int * year, int * month) nogil:
361- year[0 ] = ordinal // 12 + 1970
362- month[0 ] = ordinal % 12 + 1
363-
364-
365360cdef int64_t asfreq_MtoDT(int64_t ordinal, asfreq_info * af_info) nogil:
366361 cdef:
367362 int64_t unix_date
368363 int year, month
369364
370365 ordinal += af_info.is_end
371- MtoD_ym(ordinal, & year, & month)
366+
367+ year = ordinal // 12 + 1970
368+ month = ordinal % 12 + 1
372369
373370 unix_date = unix_date_from_ymd(year, month, 1 )
374371 unix_date -= af_info.is_end
@@ -449,10 +446,7 @@ cdef int64_t asfreq_DTtoA(int64_t ordinal, asfreq_info *af_info) nogil:
449446
450447 ordinal = downsample_daytime(ordinal, af_info)
451448 pandas_datetime_to_datetimestruct(ordinal, NPY_FR_D, & dts)
452- if dts.month > af_info.to_end:
453- return < int64_t> (dts.year + 1 - 1970 )
454- else :
455- return < int64_t> (dts.year - 1970 )
449+ return dts_to_year_ordinal(& dts, af_info.to_end)
456450
457451
458452cdef int DtoQ_yq(int64_t ordinal, asfreq_info * af_info, npy_datetimestruct* dts) nogil:
@@ -483,7 +477,7 @@ cdef int64_t asfreq_DTtoM(int64_t ordinal, asfreq_info *af_info) nogil:
483477
484478 ordinal = downsample_daytime(ordinal, af_info)
485479 pandas_datetime_to_datetimestruct(ordinal, NPY_FR_D, & dts)
486- return < int64_t > (( dts.year - 1970 ) * 12 + dts.month - 1 )
480+ return dts_to_month_ordinal( & dts)
487481
488482
489483cdef int64_t asfreq_DTtoW(int64_t ordinal, asfreq_info * af_info) nogil:
@@ -716,6 +710,40 @@ cdef int64_t unix_date_from_ymd(int year, int month, int day) nogil:
716710 return unix_date
717711
718712
713+ cdef inline int64_t dts_to_month_ordinal(npy_datetimestruct* dts) nogil:
714+ # AKA: use npy_datetimestruct_to_datetime(NPY_FR_M, &dts)
715+ return < int64_t> ((dts.year - 1970 ) * 12 + dts.month - 1 )
716+
717+
718+ cdef inline int64_t dts_to_year_ordinal(npy_datetimestruct * dts, int to_end) nogil:
719+ cdef:
720+ int64_t result
721+
722+ result = npy_datetimestruct_to_datetime(NPY_DATETIMEUNIT.NPY_FR_Y, dts)
723+ if dts.month > to_end:
724+ return result + 1
725+ else :
726+ return result
727+
728+
729+ cdef inline int64_t dts_to_qtr_ordinal(npy_datetimestruct* dts, int to_end) nogil:
730+ cdef:
731+ int quarter
732+
733+ adjust_dts_for_qtr(dts, to_end)
734+ quarter = month_to_quarter(dts.month)
735+ return < int64_t> ((dts.year - 1970 ) * 4 + quarter - 1 )
736+
737+
738+ cdef inline int get_anchor_month(int freq, int freq_group) nogil:
739+ cdef:
740+ int fmonth
741+ fmonth = freq - freq_group
742+ if fmonth == 0 :
743+ fmonth = 12
744+ return fmonth
745+
746+
719747# specifically _dont_ use cdvision or else ordinals near -1 are assigned to
720748# incorrect dates GH#19643
721749@ cython.cdivision (False )
@@ -740,23 +768,12 @@ cdef int64_t get_period_ordinal(npy_datetimestruct *dts, int freq) nogil:
740768 freq_group = get_freq_group(freq)
741769
742770 if freq_group == FR_ANN:
743- fmonth = freq - FR_ANN
744- if fmonth == 0 :
745- fmonth = 12
746-
747- mdiff = dts.month - fmonth
748- if mdiff <= 0 :
749- return dts.year - 1970
750- else :
751- return dts.year - 1970 + 1
771+ fmonth = get_anchor_month(freq, freq_group)
772+ return dts_to_year_ordinal(dts, fmonth)
752773
753774 elif freq_group == FR_QTR:
754- fmonth = freq - FR_QTR
755- if fmonth == 0 :
756- fmonth = 12
757-
758- mdiff = dts.month - fmonth + 12
759- return (dts.year - 1970 ) * 4 + (mdiff - 1 ) // 3
775+ fmonth = get_anchor_month(freq, freq_group)
776+ return dts_to_qtr_ordinal(dts, fmonth)
760777
761778 elif freq_group == FR_WK:
762779 unix_date = npy_datetimestruct_to_datetime(NPY_FR_D, dts)
0 commit comments