I have a use case like this in Python: Find the 1st business day and last business day of the previous month based on a date. For example if date is 2024-06-10
first_business_day = '2024-05-01'
last_business_day = '2024-05-31'
I have tried like below
run_date = '2024-06-10'
from datetime import datetime, timedelta
d = datetime.strptime(run_date, '%Y-%m-%d').date()
previous_month_first_business_day = (d - timedelta(days=d.day)).replace(day=1).strftime("%Y-%m-%d")
previous_month_last_business_day = (d - timedelta(days=d.day)).strftime("%Y-%m-%d")
Result:
previous_month_first_business_day = '2024-05-01'
previous_month_last_business_day = '2024-05-31'
This is working fine for month of May, but when I want the same result for June, then using the above I am getting:
previous_month_first_business_day = '2024-06-01' # This should be '2024-06-03'
previous_month_last_business_day = '2024-06-30' # This should be '2024-06-29'
What should I do to achieve the right result?
Take a look at the builtin calendar
instead of just datetime
import calendar
import datetime
def month_start_end_work(date_src, fmt_date="%Y-%m-%d"):
dt = datetime.datetime.strptime(date_src, fmt_date)
# roll around January -> December
month = 12 if dt.month == 1 else (dt.month - 1)
year = dt.year if month != 12 else (dt.year - 1)
# discover last day of last month
for day in (31, 30, 29, 28): # handle Feb cases
try: # already the correct year for leap
month_start = calendar.weekday(year, month, day)
except ValueError: # day is out of range for month
continue # month has fewer days (always decreases)
if month_start == calendar.SATURDAY:
day -= 1
elif month_start == calendar.SUNDAY:
day -= 2
break # last day name to be used
else: # did not solve and break
raise RuntimeError("BUG: impossible code path reached")
day_last = (year, month, day) # TODO may want to make a datetime.datetime
# discover first day of last month
day = 1 # all months begin at 1
month_start = calendar.weekday(year, month, day)
if month_start == calendar.SATURDAY:
day += 2
elif month_start == calendar.SUNDAY:
day += 1
day_first = (year, month, day)
return day_first, day_last
>>> month_start_end_work("2024-06-10")
((2024, 5, 1), (2024, 5, 31))
>>> month_start_end_work("2024-07-10")
((2024, 6, 3), (2024, 6, 28))
>>> month_start_end_work("2022-01-01")
((2021, 12, 1), (2021, 12, 31))
If you have special days you know are days off (probably 6-12 annually), collect them into a list and just keep decrementing/incrementing for exact matches