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
andd-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
How to Sort Unicode Strings Alphabetically in Python
How to Flatten a Nested JSON Recursively, with Flatten_JSON
Is There a Math Ncr Function in Python
How to Find All the Subsets of a Set, with Exactly N Elements
Elegant Python Function to Convert Camelcase to Snake_Case
How to Validate a Url in Python? (Malformed or Not)
Access Elementtree Node Parent Node
Multiple Modeladmins/Views for Same Model in Django Admin
How to Udp Multicast in Python
How to Pretty-Print Ascii Tables with Python
Python Numpy Valueerror: Operands Could Not Be Broadcast Together with Shapes
Using Backslash in Python (Not to Escape)
Maximum Value for Long Integer
Traverse a List in Reverse Order in Python
Color by Column Values in Matplotlib
Why Does Python Print Unicode Characters When the Default Encoding Is Ascii