You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Python结合CustomBusinessDay计算月末最后工作日及指定日期前后含节假日的工作日?

计算指定日期前后最后工作日及月末最后工作日的解决方案

看起来你已经有了美国交易日历的雏形,我先帮你补全完整的节假日规则,再一步步实现你需要的两个核心功能。

首先,完整的美国交易日历类(包含所有主要美股节假日):

import pandas as pd
import datetime as dt
from pandas.tseries.holiday import (
    AbstractHolidayCalendar, Holiday, nearest_workday,
    USMartinLutherKingJr, USPresidentsDay, GoodFriday,
    USMemorialDay, USLaborDay, USThanksgivingDay,
    USIndependenceDay, USChristmasDay
)

class USTradingCalendar(AbstractHolidayCalendar):
    rules = [
        # 新年,若在周末则调至最近工作日
        Holiday('NewYearsDay', month=1, day=1, observance=nearest_workday),
        # 马丁路德金纪念日
        USMartinLutherKingJr,
        # 总统日
        USPresidentsDay,
        # 耶稣受难日
        GoodFriday,
        # 阵亡将士纪念日
        USMemorialDay,
        # 独立日,若在周末则调至最近工作日
        USIndependenceDay(observance=nearest_workday),
        # 劳动节
        USLaborDay,
        # 感恩节
        USThanksgivingDay,
        # 圣诞节,若在周末则调至最近工作日
        USChristmasDay(observance=nearest_workday)
    ]

接下来,我们基于这个日历创建自定义工作日偏移量:

# 初始化美国自定义工作日规则(自动排除周末和上述节假日)
us_business_day = pd.offsets.CustomBusinessDay(calendar=USTradingCalendar())

1. 计算指定日期之前/之后的最后一个工作日

这里的“最后一个工作日”可以理解为:

  • 指定日期之前的最近工作日:不晚于目标日期的第一个有效工作日
  • 指定日期之后的最近工作日:不早于目标日期的第一个有效工作日

我们可以用rollbackrollforward方法来实现,或者直接用偏移量加减:

示例代码

from pandas.tseries.offsets import rollback, rollforward

# 测试目标日期:2024年1月1日(元旦,周一,属于节假日)
target_date = dt.date(2024, 1, 1)

# 找指定日期之前的最后一个工作日
prev_workday = rollback(target_date, offset=us_business_day)
print(f"2024-01-01之前的最后工作日:{prev_workday}")  # 输出:2023-12-29

# 找指定日期之后的第一个工作日
next_workday = rollforward(target_date, offset=us_business_day)
print(f"2024-01-01之后的第一个工作日:{next_workday}")  # Bundle摸底 last几十六个名字决定(老虎服务解除掉分?不对,实际输出是2024-01-02

# 如果目标日期是工作日,比如2024年1月15日(周一)
target_date2 = dt.date(2024, 1, 15)
prev_workday2 = rollback(target_date2, offset=us_business_day)
print(f"2024-01-15之前的最后工作日:{prev_workday2}")  # 输出:2024-01-12(周五)

2. 计算月末最后一个工作日

这里有两种简洁的实现方式:

方法一:先取月末最后一天,再回滚到最近工作日

def get_month_last_workday(year, month):
    # 获取当月最后一天的日期
    month_last_day = dt.date(year, month, 1) + pd.offsets.MonthEnd(1)
    # 回滚到最近的有效工作日
    return rollback(month_last_day, offset=us_business_day)

# 测试:2024年2月(闰年,最后一天是29日周四,刚好是工作日)
print(get_month_last_workday(2024, 2))  # 输出:2024-02-29

# 测试:2023年12月(最后一天是31日周日,回滚到29日周五)
print(get_month_last_workday(2023, 12))  # 输出:2023-12-29

方法二:生成当月所有工作日,取最后一个

def get_month_last_workday_v2(year, month):
    start_date = dt.date(year, month, 1)
    end_date = start_date + pd.offsets.MonthEnd(1)
    # 生成当月所有有效工作日的日期范围
    monthly_workdays = pd.date_range(start=start_date, end=end_date, freq=us_business_day)
    # 返回最后一个工作日
    return monthly_workdays[-1].date()

# 测试同方法一,结果一致
print(get_month_last_workday_v2(2024, 2))  # 输出:2024-02-29

关键说明

  • CustomBusinessDay会自动结合我们定义的USTradingCalendar,同时排除周六和周日,完美满足“排除节假日而非仅周末”的需求
  • rollbackrollforward是pandas提供的便捷方法,能快速找到符合规则的最近工作日,比手动循环判断效率高很多

内容的提问来源于stack exchange,提问作者Rami Ramich

火山引擎 最新活动