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

如何在Pandas中生成含工作日逻辑的指定日月度日期范围?

解决Pandas中生成考虑工作日的月度固定日期范围问题

没错,Pandas自带的偏移别名大多围绕月初、月末这类节点,确实没有直接支持每月固定日期(比如20号)还能自动调整到工作日的现成方法。不过咱们可以拆成两步来搞定:先生成每月固定日的基础序列,再把非工作日调整成合规的工作日。下面分正向、反向两个场景给你详细说明:

正向场景:从指定日期开始,生成每月固定日的工作日日期

需求:从2017-12-20开始,每月按20日生成日期(共5个),若当日非工作日则顺延至下一个工作日,后续仍以20日为基准。

步骤1:生成每月20号的基础日期序列

咱们可以先构造出每月20号的原始日期,这里用MS(月初)偏移量加上19天,就能精准定位到每个月的20号:

import pandas as pd
import numpy as np

# 生成基础的每月20号日期
base_dates = pd.date_range(start='2017-12-20', periods=5, freq='MS') + pd.DateOffset(days=19)
# 输出示例:DatetimeIndex(['2017-12-20', '2018-01-20', '2018-02-20', '2018-03-20', '2018-04-20'], dtype='datetime64[ns]', freq=None)

步骤2:调整为下一个工作日

用np.busday_offset函数,设置roll='forward'就能实现「非工作日顺延至下一个工作日」的逻辑:

# 转换为datetime64格式后调整工作日
adjusted_dates = np.busday_offset(base_dates.astype('datetime64[D]'), 0, roll='forward')
# 转回Pandas DatetimeIndex格式
adjusted_dt_range = pd.DatetimeIndex(adjusted_dates)

print(adjusted_dt_range)

举个例子,如果2018-02-20是周二(工作日)就直接保留;要是当天是周六,就会自动调整为2018-02-22(下周一)。

反向场景:以指定日期为终点,倒推生成每月固定日的工作日日期

需求:以2018-05-20为终点,倒推生成5个每月20号的日期,若当日非工作日则倒推至上一个工作日。

步骤1:生成倒推的每月20号基础日期

用date_range的end参数结合-MS(倒推月初)偏移量,就能生成倒序的每月20号基础日期:

# 倒推生成基础的每月20号日期
base_dates_reverse = pd.date_range(end='2018-05-20', periods=5, freq='-MS') + pd.DateOffset(days=19)
# 输出示例:DatetimeIndex(['2018-05-20', '2018-04-20', '2018-03-20', '2018-02-20', '2018-01-20'], dtype='datetime64[ns]', freq=None)

步骤2:调整为上一个工作日

这次把roll参数设为'backward',就能实现「非工作日倒推至上一个工作日」的逻辑:

adjusted_dates_reverse = np.busday_offset(base_dates_reverse.astype('datetime64[D]'), 0, roll='backward')
adjusted_dt_range_reverse = pd.DatetimeIndex(adjusted_dates_reverse)

print(adjusted_dt_range_reverse)

比如如果2018-01-20是周六,就会自动调整为2018-01-19(周五)。

额外优化:封装成可复用函数

如果需要多次使用这个逻辑,可以把它封装成一个函数,方便随时调用:

def get_monthly_business_dates(start=None, end=None, periods=None, day_of_month=20, roll_direction='forward'):
    # 生成基础日期序列
    if start:
        base_dates = pd.date_range(start=start, periods=periods, freq='MS') + pd.DateOffset(days=day_of_month-1)
    elif end:
        base_dates = pd.date_range(end=end, periods=periods, freq='-MS') + pd.DateOffset(days=day_of_month-1)
    else:
        raise ValueError("必须提供'start'或'end'参数中的一个")
    
    # 调整为工作日
    adjusted_dates = np.busday_offset(base_dates.astype('datetime64[D]'), 0, roll=roll_direction)
    return pd.DatetimeIndex(adjusted_dates)

# 正向场景调用
forward_dates = get_monthly_business_dates(start='2017-12-20', periods=5, day_of_month=20)
# 反向场景调用
reverse_dates = get_monthly_business_dates(end='2018-05-20', periods=5, day_of_month=20, roll_direction='backward')

这样不管你要生成哪个固定日期的月度工作日序列,都能轻松搞定啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 17:47:37