Most Recent Previous Business Day in Python

Most recent previous business day in Python

Use pandas!

import datetime
# BDay is business day, not birthday...
from pandas.tseries.offsets import BDay

today = datetime.datetime.today()
print(today - BDay(4))

Since today is Thursday, Sept 26, that will give you an output of:

datetime.datetime(2013, 9, 20, 14, 8, 4, 89761)

How can you get the most recent business day in Python?

You can use:

import pandas as pd

pd.datetime.today() - pd.tseries.offsets.BDay(0)

Update

today = pd.datetime(2018,9,2)

np.where((today - pd.tseries.offsets.BDay(0)) > today,
(today - pd.tseries.offsets.BDay(1)),
(today - pd.tseries.offsets.BDay(0)))

[output]
Timestamp('2018-08-31 00:00:00')

Get previous business day in a DataFrame

Pandas supports providing your own holidays via Custom Business Days.

The benefit of this solution is it supports adjacent holidays seamlessly; for example, Boxing Day & Christmas in some regions.

# define custom business days
weekmask = 'Mon Tue Wed Thu Fri'
holidays = ['2018-10-11']

bday = pd.tseries.offsets.CustomBusinessDay(holidays=holidays, weekmask=weekmask)

# construct mask to identify when days must be sutracted
m1 = df['category'] == 'B'
m2 = df['day'].dt.weekday.isin([5, 6]) | df['day'].isin(holidays)

# apply conditional logic
df['day'] = np.where(m1 & m2, df['day'] - bday, df['day'])

print(df)

category day
0 A 2018-10-10
1 B 2018-10-10
2 C 2018-10-12
3 B 2018-10-12
4 C 2018-10-14
5 A 2018-10-15

Edit: On the basis of your comment, "I just realised I didn't ask exactly what I wanted. I want to find the previous business day", you can simply use:

df['day'] -= bday

Listing the previous N business days

Subtracting days from a date

You can subtract 30 days from a datetime.datetime object by subtracting a datetime.timedelta object:

>>> import datetime
>>> datetime.datetime.today()
datetime.datetime(2020, 10, 31, 10, 20, 0, 704133)
>>> datetime.datetime.today() - datetime.timedelta(30)
datetime.datetime(2020, 10, 1, 10, 19, 49, 680385)
>>> datetime.datetime.strptime('2020-01-30', '%Y-%m-%d') - datetime.timedelta(30)
datetime.datetime(2019, 12, 31, 0, 0)

Skipping week-ends by subtracting 7 days instead of 5

We are starting from date d and you want to subtract N=30 non-week-end days. A general way could be:

  • Figure out which day of the week is d;
  • Figure out how many week-ends there are between d and d-N;
  • Remove the appropriate number of days.

However, you want to subtract 30 days, and 30 is a multiple of 5. This makes things particularly easy: when you subtract 5 days from a date, you are guaranteed to encounter exactly one week-end in those five days. So you can immediately remove 7 days instead of 5.

Removing 30 days is the same as removing 6 times 5 days. So you can remove 6 times 7 days instead, which is achieved by subtracting datetime.timedelta(42) from your date.

Note: this accounts for week-ends, but not for special holidays.

Skipping week-ends iteratively

You can test for days of the week using .weekday(). This is already answered on this other question: Loop through dates except for week-ends

Previous weekday in Python

Simply subtract a day from the given date, then check if the date is a weekday. If not, subtract another, until you do have a weekday:

from datetime import date, timedelta
def prev_weekday(adate):
adate -= timedelta(days=1)
while adate.weekday() > 4: # Mon-Fri are 0-4
adate -= timedelta(days=1)
return adate

Demo:

>>> prev_weekday(date.today())
datetime.date(2012, 8, 20)
>>> prev_weekday(date(2012, 8, 20))
datetime.date(2012, 8, 17)

Alternatively, use an offset table; no need to make this a mapping, a tuple will do just fine:

_offsets = (3, 1, 1, 1, 1, 1, 2)
def prev_weekday(adate):
return adate - timedelta(days=_offsets[adate.weekday()])

selecting Business date taking into account for Holidays

So this work for me.
One downside is the list of Holidays have to be manually updated when required.

# Date Setup

holidaylist = pd.read_csv('holiday.csv')
holidaylist['Date'] = pd.to_datetime(holidaylist['Date'])

# enddate = date(2020, 12, 28)
enddate = datetime.today() - timedelta(days = 1)
while enddate in holidaylist.values or datetime.weekday(enddate) == 6 or datetime.weekday(enddate) == 5:
enddate = enddate - timedelta(days = 1)

begdate = enddate - timedelta(days = 1)
while begdate in holidaylist.values or datetime.weekday(begdate) == 6 or datetime.weekday(begdate) == 5:
begdate = begdate - timedelta(days = 1)

ed = enddate.strftime("%Y-%m-%d")
bd = begdate.strftime("%Y-%m-%d")

# print(ed,bd)

How can I convert Date Column to the last Business Day of that Date

Here is how I usually do it:

import pandas as pd

data = {'Name': ['2021-12-31', '2020-12-31', '2019-12-31', '2018-12-31', '2017-12-31']}

td = pd.Timedelta('1 day')
bd = pd.tseries.offsets.BusinessDay(n=-1)

data_EOM = {'NAME': [pd.Timestamp(ts) + td + bd for ts in data['Name']]}

td is used to shift the End-of-month date to the next month.
bd is used to go back a single business date, ergo the last business day of the month you want.
pd.Timestamp() is used to convert the string date into a timestamp object on which the timedelta objects above (td and bd) can be applied.

Finally, I use list comprehension to loop through the original date list to create the EOM date list you were looking for. From here, you can create your df just like you wanted.

Hope this helps!

Determine if a day is a business day in Python / Pandas

Since len of pd.bdate_range() tells us how many business days are in the supplied range of dates, we can cast this to a bool to determine if a range of a single day is a business day:

def is_business_day(date):
return bool(len(pd.bdate_range(date, date)))


Related Topics



Leave a reply



Submit