Looking for a clean function for this, ideally in Pandas/Numpy. I'm currently building something messy out of CustomBusinessHour() and TimeDelta() functions from Pandas, but I think that there must be a better way. If Pandas had a CustomBusinessMinute() feature, this would be as easy as len(pd.date_range(timestamp1,timestamp,freq=CustomBusinessMinute())).
By "Business Minute," I mean a minute that meets certain criteria. For example, in my case this means 1) does not fall on weekend, 2) falls between 9am and 5pm, and 3) does not fall on Federal Holiday.
Thanks
Consider the following:
You will only have to closely examine the aspects of the start and end dates. IE Carefully calculate the business minutes for those two days.
For every other date in between, you only need to know one or things (1) If it's a weekday and if it is: (2) is it a Federal Holiday
For every qualifying date in the date range, you know exactly how many "Business minutes" are in each day: 480 minutes.
Pandas offers a way to get business days based on US Federal Holidays. That takes care of the hardest part. The rest should be easy to implement.
There's probably a more elegant way, but here's something to start with. Most of the code is for dealing with the start and end dates. Getting all the minutes in between is about 4 lines.
from dateutil.relativedelta import relativedelta
import pandas as pd
from pandas.tseries.offsets import CDay
from pandas.tseries.holiday import USFederalHolidayCalendar
business_day = CDay(calendar=USFederalHolidayCalendar())
def is_weekday(dt):
return dt.weekday() < 5
def is_holiday(dt):
return not len(pd.date_range(dt, dt, freq=business_day))
def weekend_or_holiday(dt):
'''helper function'''
if not is_weekday(dt):
return True
if is_holiday(dt):
return True
return False
def start_day_minutes(dt, end_of_day=None):
'''returns number of business minutes left in the day given a start datetime'''
if not end_of_day:
end_of_day = dt.replace(hour=17, minute=0)
if dt > end_of_day or weekend_or_holiday(dt):
return 0
num_of_minutes = (end_of_day - dt).seconds / 60
return num_of_minutes
def end_day_minutes(dt):
'''like start_day_minutes, but for the ending day.'''
start_of_day = dt.replace(hour=9, minute=0)
if dt < start_of_day or weekend_or_holiday(dt):
return 0
num_of_minutes = (dt - start_of_day).seconds / 60
return num_of_minutes
def business_minutes(t1, t2):
'''returns num of busniess minutes between t1 and t2'''
start = t1.replace(hour=0, minute=0) + relativedelta(days=1)
end = t2.replace(hour=0, minute=0) + relativedelta(days=-1)
days_between = pd.date_range(start, end, freq=business_day)
minutes_between = (len(days_between) * 480)
if (t1.year, t1.day) == (t2.year, t2.day):
start_end_minutes = start_day_minutes(t1, t2)
else:
start_end_minutes = start_day_minutes(t1) + end_day_minutes(t2)
minutes = minutes_between + start_end_minutes
return minutes
Example:
start=datetime(2016,1,1)
end=datetime(2017,1,1)
print(business_minutes(start,end))
#120480
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With