如何修正月末最后工作日计算Python函数并集成节假日校验?
问题描述
我正在编写一个筛选月末最后工作日的函数,目前遇到以下问题:
当前函数获取的是上月最后工作日,但假设上月最后工作日为周五时,我需要将日期调整至下一个工作日(即周一),但实际结果却跳到了周六。请问如何修改函数使其仅返回工作日?同时如何集成我已有的节假日表进行校验?
现有代码
import calendar from datetime import date import pandas as pd from datetime import timedelta def BsDay(): today = date.today() last_day = max(calendar.monthcalendar(today.year, today.month)[-1:][0][:5]) validDay = (today.year, today.month-1, max(calendar.monthcalendar(today.year, today.month-1)[-1:][0][:5])) if today.month == 1 and today.day <= last_day: validDay = (today.year-1, today.month+11, max(calendar.monthcalendar(today.year, today.month-1)[-1:][0][:5])) elif today.day <= last_day: validDay else: validDay = (today.year, today.month, max( calendar.monthcalendar(today.year, today.month)[-1:][0][:5])) return validDay
尝试的代码及输出
BusinessDay = ''.join(map(str, BsDay())) BusinessDay = BusinessDay[0:4] + '-0' + BusinessDay[4]+'-'+BusinessDay[5:7] dateD='2022-07-29' dateD=pd.to_datetime(dateD) dateF=pd.to_datetime(BusinessDay) LastDayNotWeekend=dateD+timedelta(days=1) print('LastDayNotWeekend not Weekend',LastDayNotWeekend) LastDayInWeekend=dateF+timedelta(days=1) print('LastDayInWeekend in Weekend->',LastDayInWeekend)
月末最后工作日不在周末时的输出:
LastDayNotWeekend not Weekend 2022-07-30 00:00:00
月末最后工作日在周末时的输出:
LastDayInWeekend in Weekend-> 2022-09-01 00:00:00
解决方案
1. 重构函数,直接返回date对象
原函数返回元组,后续字符串拼接容易出格式bug(比如10月会被拆成010),改成直接返回date类型,逻辑更清晰:
import calendar from datetime import date, timedelta import pandas as pd def get_last_business_day(): today = date.today() # 确定目标月份:当前日 <= 当月最后工作日则取上月,否则取当月 current_month_last_workday = max(calendar.monthcalendar(today.year, today.month)[-1][:5]) if today.day <= current_month_last_workday: target_year = today.year - 1 if today.month == 1 else today.year target_month = 12 if today.month == 1 else today.month - 1 else: target_year = today.year target_month = today.month # 取目标月份周一到周五的最后一天 last_week = calendar.monthcalendar(target_year, target_month)[-1] last_workday = max(last_week[:5]) return date(target_year, target_month, last_workday)
2. 处理周五转周一的逻辑
按需求,只要候选日是周五,直接跳转到下周一:
def get_adjusted_business_day(): candidate = get_last_business_day() # weekday()返回0=周一,4=周五 if candidate.weekday() == 4: candidate += timedelta(days=3) # 保险校验:防止调整后意外碰到周末(虽然加3天肯定是周一) while candidate.weekday() >= 5: candidate += timedelta(days=1) return candidate
3. 集成节假日表校验
假设你的节假日表是pandas.DataFrame,包含holiday_date列存储节假日日期。把节假日转成集合快速查询,循环向后找第一个非节假日的工作日:
def get_final_valid_workday(holiday_df): adjusted_date = get_adjusted_business_day() # 把节假日转成date集合,查询效率更高 holiday_set = set(holiday_df['holiday_date'].dt.date) while True: # 检查是否是周末或节假日 if adjusted_date.weekday() >= 5 or adjusted_date in holiday_set: adjusted_date += timedelta(days=1) else: break return adjusted_date
测试用例
# 模拟节假日表,比如2022-09-01是节假日 holiday_df = pd.DataFrame({'holiday_date': pd.to_datetime(['2022-09-01'])}) print(get_final_valid_workday(holiday_df))
关键修复点
- 删掉原函数里无效的
elif today.day <= last_day: validDay代码 - 用
date对象替代字符串拼接,彻底解决日期格式错误 - 节假日用集合存储,比DataFrame直接查询快数倍
- 循环校验确保最终返回的一定是合法工作日
内容的提问来源于stack exchange,提问作者Zan
相关产品推荐
相关产品推荐

