Datetime Python - Next Business Day

doing more than one business day

def next_business_day(start_day, business_days, HOLIDAYS):
    ONE_DAY = datetime.timedelta(days=1)
    temp_day = start_day
    for i in range(0, business_days):
        next_day = temp_day + ONE_DAY
        while next_day.weekday() in [5,6] or next_day in HOLIDAYS:
            next_day += ONE_DAY
        temp_day = next_day
    return temp_day

This question is common and there are different levels of solutions:

Simplest: use something like your approach of checking the weekday. One common idom is something like

d = datetime.date(2012,2,7)
next = d + datetime.timedelta(days= 7-d.weekday() if d.weekday()>3 else 1)

Once you want holidays, you can roll your own datetime "TradingDateChecker" that has to scan for the "predictable" holidays like Jan 1, July 4, Dec 25 the Friday before or Monday after those if they fall on a weekend, last Monday in May, first Monday in Sept etc.

I won't even bother posting that code here because for trading holidays, it still is insufficient.

  • Good Friday the NYSE is closed and futures and bond markets are open
  • Columbus day and Veterans Day, the banks are closed and the stock market is open.

The stock and futures markets have different holidays. If you want NYSE holidays (a common request) see below. You can't really get around keeping your own calendar since the closing dates are usually only announced for a couple of years in the future.

# For a longer list of NYSE closed dates see: http://www.chronos-st.org/NYSE_Observed_Holidays-1885-Present.html
holidays = [datetime.date(2000, 1, 17),
 datetime.date(2000, 2, 21),
 datetime.date(2000, 4, 21),
 datetime.date(2000, 5, 29),
 datetime.date(2000, 7, 4),
 datetime.date(2000, 9, 4),
 datetime.date(2000, 11, 23),
 datetime.date(2000, 12, 25),
 datetime.date(2001, 1, 1),
 datetime.date(2001, 1, 15),
 datetime.date(2001, 2, 19),
 datetime.date(2001, 5, 28),
 datetime.date(2001, 7, 4),
 datetime.date(2001, 9, 3),
 datetime.date(2001, 9, 11),
 datetime.date(2001, 9, 12),
 datetime.date(2001, 9, 13),
 datetime.date(2001, 9, 14),
 datetime.date(2001, 11, 22),
 datetime.date(2001, 12, 25),
 datetime.date(2002, 1, 1),
 datetime.date(2002, 1, 21),
 datetime.date(2002, 2, 18),
 datetime.date(2002, 3, 29),
 datetime.date(2002, 5, 27),
 datetime.date(2002, 7, 4),
 datetime.date(2002, 9, 2),
 datetime.date(2002, 11, 28),
 datetime.date(2002, 12, 25),
 datetime.date(2003, 1, 1),
 datetime.date(2003, 1, 20),
 datetime.date(2003, 2, 17),
 datetime.date(2003, 4, 18),
 datetime.date(2003, 5, 26),
 datetime.date(2003, 7, 4),
 datetime.date(2003, 9, 1),
 datetime.date(2003, 11, 27),
 datetime.date(2003, 12, 25),
 datetime.date(2004, 1, 1),
 datetime.date(2004, 1, 19),
 datetime.date(2004, 2, 16),
 datetime.date(2004, 4, 9),
 datetime.date(2004, 5, 31),
 datetime.date(2004, 6, 11),
 datetime.date(2004, 7, 5),
 datetime.date(2004, 9, 6),
 datetime.date(2004, 11, 25),
 datetime.date(2004, 12, 24),
 datetime.date(2005, 1, 17),
 datetime.date(2005, 2, 21),
 datetime.date(2005, 3, 25),
 datetime.date(2005, 5, 30),
 datetime.date(2005, 7, 4),
 datetime.date(2005, 9, 5),
 datetime.date(2005, 11, 24),
 datetime.date(2005, 12, 26),
 datetime.date(2006, 1, 2),
 datetime.date(2006, 1, 16),
 datetime.date(2006, 2, 20),
 datetime.date(2006, 4, 14),
 datetime.date(2006, 5, 29),
 datetime.date(2006, 7, 4),
 datetime.date(2006, 9, 4),
 datetime.date(2006, 11, 23),
 datetime.date(2006, 12, 25),
 datetime.date(2007, 1, 1),
 datetime.date(2007, 1, 2),
 datetime.date(2007, 1, 15),
 datetime.date(2007, 2, 19),
 datetime.date(2007, 4, 6),
 datetime.date(2007, 5, 28),
 datetime.date(2007, 7, 4),
 datetime.date(2007, 9, 3),
 datetime.date(2007, 11, 22),
 datetime.date(2007, 12, 25),
 datetime.date(2008, 1, 1),
 datetime.date(2008, 1, 21),
 datetime.date(2008, 2, 18),
 datetime.date(2008, 3, 21),
 datetime.date(2008, 5, 26),
 datetime.date(2008, 7, 4),
 datetime.date(2008, 9, 1),
 datetime.date(2008, 11, 27),
 datetime.date(2008, 12, 25),
 datetime.date(2009, 1, 1),
 datetime.date(2009, 1, 19),
 datetime.date(2009, 2, 16),
 datetime.date(2009, 4, 10),
 datetime.date(2009, 5, 25),
 datetime.date(2009, 7, 3),
 datetime.date(2009, 9, 7),
 datetime.date(2009, 11, 26),
 datetime.date(2009, 12, 25),
 datetime.date(2010, 1, 1),
 datetime.date(2010, 1, 18),
 datetime.date(2010, 2, 15),
 datetime.date(2010, 4, 2),
 datetime.date(2010, 5, 31),
 datetime.date(2010, 7, 5),
 datetime.date(2010, 9, 6),
 datetime.date(2010, 11, 25),
 datetime.date(2010, 12, 24),
 datetime.date(2011, 1, 17),
 datetime.date(2011, 2, 21),
 datetime.date(2011, 4, 22),
 datetime.date(2011, 5, 30),
 datetime.date(2011, 7, 4),
 datetime.date(2011, 9, 5),
 datetime.date(2011, 11, 24),
 datetime.date(2011, 12, 26),
 datetime.date(2012, 1, 2),
 datetime.date(2012, 1, 16),
 datetime.date(2012, 2, 20),
 datetime.date(2012, 4, 6),
 datetime.date(2012, 5, 28),
 datetime.date(2012, 7, 4),
 datetime.date(2012, 9, 3),
 datetime.date(2012, 11, 22),
 datetime.date(2012, 12, 25),
 datetime.date(2013, 1, 1),
 datetime.date(2013, 1, 21),
 datetime.date(2013, 2, 18),
 datetime.date(2013, 3, 29),
 datetime.date(2013, 5, 27),
 datetime.date(2013, 7, 4),
 datetime.date(2013, 9, 2),
 datetime.date(2013, 11, 28),
 datetime.date(2013, 12, 25)]

I used the holidays package.

$ pip install holidays

Here is the function I made to determine the next business day after today.

import datetime
import holidays

ONE_DAY = datetime.timedelta(days=1)
HOLIDAYS_US = holidays.US()

def next_business_day():
    next_day = datetime.date.today() + ONE_DAY
    while next_day.weekday() in holidays.WEEKEND or next_day in HOLIDAYS_US:
        next_day += ONE_DAY
    return next_day

It will return tomorrow's date, if tomorrow is not a weekend and not a holiday. Otherwise it will find the next* day that isn't either of those things. Example run on Wednesday, 15 March 2017:

>>> next_business_day()
datetime.date(2017, 3, 16)

* Caution, in the event President Camacho declares every day a holiday, this could infinite loop.


I would use dateutil.rrule:

import datetime
from dateutil import rrule


holidays = [
    datetime.date(2012, 5, 1,),
    datetime.date(2012, 6, 1,),
    # ...
]

# Create a rule to recur every weekday starting today
r = rrule.rrule(rrule.DAILY,
                byweekday=[rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR],
                dtstart=datetime.date.today())

# Create a rruleset
rs = rrule.rruleset()

# Attach our rrule to it
rs.rrule(r)

# Add holidays as exclusion days
for exdate in holidays:
    rs.exdate(exdate)


print rs[0]