@@ -24,7 +24,7 @@ from frequencies cimport get_freq_code
2424from nattype cimport NPY_NAT
2525from np_datetime cimport (pandas_datetimestruct,
2626 dtstruct_to_dt64, dt64_to_dtstruct,
27- is_leapyear, days_per_month_table)
27+ is_leapyear, days_per_month_table, dayofweek )
2828
2929# ---------------------------------------------------------------------
3030# Constants
@@ -145,45 +145,44 @@ def apply_index_wraps(func):
145145# ---------------------------------------------------------------------
146146# Business Helpers
147147
148- cpdef int get_lastbday(int wkday , int days_in_month) :
148+ cpdef int get_lastbday(int year , int month) nogil :
149149 """
150150 Find the last day of the month that is a business day.
151151
152- (wkday, days_in_month) is the output from monthrange(year, month)
153-
154152 Parameters
155153 ----------
156- wkday : int
157- days_in_month : int
154+ year : int
155+ month : int
158156
159157 Returns
160158 -------
161159 last_bday : int
162160 """
161+ cdef:
162+ int wkday, days_in_month
163+
164+ wkday = dayofweek(year, month, 1 )
165+ days_in_month = get_days_in_month(year, month)
163166 return days_in_month - max (((wkday + days_in_month - 1 ) % 7 ) - 4 , 0 )
164167
165168
166- cpdef int get_firstbday(int wkday , int days_in_month = 0 ) :
169+ cpdef int get_firstbday(int year , int month) nogil :
167170 """
168171 Find the first day of the month that is a business day.
169172
170- (wkday, days_in_month) is the output from monthrange(year, month)
171-
172173 Parameters
173174 ----------
174- wkday : int
175- days_in_month : int, default 0
175+ year : int
176+ month : int
176177
177178 Returns
178179 -------
179180 first_bday : int
180-
181- Notes
182- -----
183- `days_in_month` arg is a dummy so that this has the same signature as
184- `get_lastbday`.
185181 """
186- cdef int first
182+ cdef:
183+ int first, wkday
184+
185+ wkday = dayofweek(year, month, 1 )
187186 first = 1
188187 if wkday == 5 : # on Saturday
189188 first = 3
@@ -556,52 +555,50 @@ def shift_months(int64_t[:] dtindex, int months, object day=None):
556555 out[i] = dtstruct_to_dt64(& dts)
557556
558557 elif day == ' business_start' :
559- for i in range (count):
560- if dtindex[i] == NPY_NAT:
561- out[i] = NPY_NAT
562- continue
558+ with nogil:
559+ for i in range (count):
560+ if dtindex[i] == NPY_NAT:
561+ out[i] = NPY_NAT
562+ continue
563563
564- dt64_to_dtstruct(dtindex[i], & dts)
565- months_to_roll = months
566- wkday, days_in_month = monthrange(dts.year, dts.month)
567- compare_day = get_firstbday(wkday, days_in_month)
564+ dt64_to_dtstruct(dtindex[i], & dts)
565+ months_to_roll = months
566+ compare_day = get_firstbday(dts.year, dts.month)
568567
569- if months_to_roll > 0 and dts.day < compare_day:
570- months_to_roll -= 1
571- elif months_to_roll <= 0 and dts.day > compare_day:
572- # as if rolled forward already
573- months_to_roll += 1
568+ if months_to_roll > 0 and dts.day < compare_day:
569+ months_to_roll -= 1
570+ elif months_to_roll <= 0 and dts.day > compare_day:
571+ # as if rolled forward already
572+ months_to_roll += 1
574573
575- dts.year = year_add_months(dts, months_to_roll)
576- dts.month = month_add_months(dts, months_to_roll)
574+ dts.year = year_add_months(dts, months_to_roll)
575+ dts.month = month_add_months(dts, months_to_roll)
577576
578- wkday, days_in_month = monthrange(dts.year, dts.month)
579- dts.day = get_firstbday(wkday, days_in_month)
580- out[i] = dtstruct_to_dt64(& dts)
577+ dts.day = get_firstbday(dts.year, dts.month)
578+ out[i] = dtstruct_to_dt64(& dts)
581579
582580 elif day == ' business_end' :
583- for i in range (count):
584- if dtindex[i] == NPY_NAT:
585- out[i] = NPY_NAT
586- continue
581+ with nogil:
582+ for i in range (count):
583+ if dtindex[i] == NPY_NAT:
584+ out[i] = NPY_NAT
585+ continue
587586
588- dt64_to_dtstruct(dtindex[i], & dts)
589- months_to_roll = months
590- wkday, days_in_month = monthrange(dts.year, dts.month)
591- compare_day = get_lastbday(wkday, days_in_month)
587+ dt64_to_dtstruct(dtindex[i], & dts)
588+ months_to_roll = months
589+ compare_day = get_lastbday(dts.year, dts.month)
592590
593- if months_to_roll > 0 and dts.day < compare_day:
594- months_to_roll -= 1
595- elif months_to_roll <= 0 and dts.day > compare_day:
596- # as if rolled forward already
597- months_to_roll += 1
591+ if months_to_roll > 0 and dts.day < compare_day:
592+ months_to_roll -= 1
593+ elif months_to_roll <= 0 and dts.day > compare_day:
594+ # as if rolled forward already
595+ months_to_roll += 1
598596
599- dts.year = year_add_months(dts, months_to_roll)
600- dts.month = month_add_months(dts, months_to_roll)
597+ dts.year = year_add_months(dts, months_to_roll)
598+ dts.month = month_add_months(dts, months_to_roll)
601599
602- wkday, days_in_month = monthrange(dts.year, dts.month)
603- dts.day = get_lastbday(wkday, days_in_month)
604- out[i] = dtstruct_to_dt64(& dts)
600+ dts.day = get_lastbday(dts.year, dts.month)
601+ out[i] = dtstruct_to_dt64(& dts)
605602
606603 else :
607604 raise ValueError (" day must be None, 'start', 'end', "
@@ -635,7 +632,7 @@ cpdef datetime shift_month(datetime stamp, int months, object day_opt=None):
635632 """
636633 cdef:
637634 int year, month, day
638- int wkday, days_in_month, dy
635+ int days_in_month, dy
639636
640637 dy = (stamp.month + months) // 12
641638 month = (stamp.month + months) % 12
@@ -645,20 +642,21 @@ cpdef datetime shift_month(datetime stamp, int months, object day_opt=None):
645642 dy -= 1
646643 year = stamp.year + dy
647644
648- wkday, days_in_month = monthrange(year, month)
649645 if day_opt is None :
646+ days_in_month = get_days_in_month(year, month)
650647 day = min (stamp.day, days_in_month)
651648 elif day_opt == ' start' :
652649 day = 1
653650 elif day_opt == ' end' :
654- day = days_in_month
651+ day = get_days_in_month(year, month)
655652 elif day_opt == ' business_start' :
656653 # first business day of month
657- day = get_firstbday(wkday, days_in_month )
654+ day = get_firstbday(year, month )
658655 elif day_opt == ' business_end' :
659656 # last business day of month
660- day = get_lastbday(wkday, days_in_month )
657+ day = get_lastbday(year, month )
661658 elif is_integer_object(day_opt):
659+ days_in_month = get_days_in_month(year, month)
662660 day = min (day_opt, days_in_month)
663661 else :
664662 raise ValueError (day_opt)
@@ -691,22 +689,22 @@ cpdef int get_day_of_month(datetime other, day_opt) except? -1:
691689
692690 """
693691 cdef:
694- int wkday, days_in_month
692+ int days_in_month
695693
696694 if day_opt == ' start' :
697695 return 1
698-
699- wkday, days_in_month = monthrange(other.year, other.month)
700- if day_opt == ' end' :
696+ elif day_opt == ' end' :
697+ days_in_month = get_days_in_month(other.year, other.month)
701698 return days_in_month
702699 elif day_opt == ' business_start' :
703700 # first business day of month
704- return get_firstbday(wkday, days_in_month )
701+ return get_firstbday(other.year, other.month )
705702 elif day_opt == ' business_end' :
706703 # last business day of month
707- return get_lastbday(wkday, days_in_month )
704+ return get_lastbday(other.year, other.month )
708705 elif is_integer_object(day_opt):
709- day = min (day_opt, days_in_month)
706+ days_in_month = get_days_in_month(other.year, other.month)
707+ return min (day_opt, days_in_month)
710708 elif day_opt is None :
711709 # Note: unlike `shift_month`, get_day_of_month does not
712710 # allow day_opt = None
0 commit comments