@@ -357,6 +357,7 @@ class _BaseOffset(object):
357357 _typ = " dateoffset"
358358 _normalize_cache = True
359359 _cacheable = False
360+ _day_opt = None
360361
361362 def __call__ (self , other ):
362363 return self .apply(other)
@@ -394,6 +395,11 @@ class _BaseOffset(object):
394395 out = ' <%s ' % n_str + className + plural + self ._repr_attrs() + ' >'
395396 return out
396397
398+ def _get_offset_day (self , datetime other ):
399+ # subclass must implement `_day_opt`; calling from the base class
400+ # will raise NotImplementedError.
401+ return get_day_of_month(other, self ._day_opt)
402+
397403
398404class BaseOffset (_BaseOffset ):
399405 # Here we add __rfoo__ methods that don't play well with cdef classes
@@ -468,7 +474,7 @@ cpdef datetime shift_month(datetime stamp, int months, object day_opt=None):
468474 return stamp.replace(year = year, month = month, day = day)
469475
470476
471- cdef int get_day_of_month(datetime other, day_opt) except ? - 1 :
477+ cpdef int get_day_of_month(datetime other, day_opt) except ? - 1 :
472478 """
473479 Find the day in `other`'s month that satisfies a DateOffset's onOffset
474480 policy, as described by the `day_opt` argument.
@@ -493,10 +499,27 @@ cdef int get_day_of_month(datetime other, day_opt) except? -1:
493499 30
494500
495501 """
502+ cdef:
503+ int wkday, days_in_month
504+
496505 if day_opt == ' start' :
497506 return 1
498- elif day_opt == ' end' :
499- return monthrange(other.year, other.month)[1 ]
507+
508+ wkday, days_in_month = monthrange(other.year, other.month)
509+ if day_opt == ' end' :
510+ return days_in_month
511+ elif day_opt == ' business_start' :
512+ # first business day of month
513+ return get_firstbday(wkday, days_in_month)
514+ elif day_opt == ' business_end' :
515+ # last business day of month
516+ return get_lastbday(wkday, days_in_month)
517+ elif is_integer_object(day_opt):
518+ day = min (day_opt, days_in_month)
519+ elif day_opt is None :
520+ # Note: unlike `shift_month`, get_day_of_month does not
521+ # allow day_opt = None
522+ raise NotImplementedError
500523 else :
501524 raise ValueError (day_opt)
502525
0 commit comments