Compute salary days in Pandas

Viewed 246

I've created a custom Calendar:

holidays_list = [...]  # list of all weekends and holidays for needed time period

class MyBusinessCalendar(AbstractHolidayCalendar):
    start_date = datetime(2011, 1, 1)
    end_date = datetime(2017, 12, 31)
    rules = [
        Holiday(name='Day Off', year=d.year, month=d.month, day=d.day) for d in holidays_list
    ]

cal = MyBusinessCalendar()

I know that salary days are the 5th and the 20th days of each month or the previous business days if these ones are days off. Therefore I take

bus_day = CustomBusinessDay(calendar=cal)
r = pd.date_range('2011-01-01', '2017-12-31', freq=bus_day)

and I'd like to compute for each day from r if it's a salary day. How can I get this?

1 Answers

The list of salary days (paydays in American English) is defined by you as:

the 5th and the 20th days of each month or the previous business days if these ones are days off

To generate the list of paydays programmatically using a holiday calendar, you can generate the list of every 6th of the month and every 21st of the month:

dates = [date(year, month, 6) for month in range(1, 13)] +
    [date(year, month, 21) for month in range(1, 13)]

Then get the previous working day, i.e. offset=-1. I'd use this:

np.busday_offset(dates, -1, roll='forward', holidays=my_holidays)

The reason I use numpy.busday_offset instead of the Pandas stuff for doing the offsets is that it is vectorized and runs very fast, whereas the Pandas busday offset logic is very slow. If the number of dates is small, it won't matter. You can still use Pandas to generate the list of holidays if you want.

Note that roll='forward' is because you want the logic to be that if the 6th is on a weekend or holiday, you roll forward to the 7th or 8th, then from there you offset -1 working day to get the payday.

Related