You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修正月末最后工作日计算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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:30:49