
本文介绍如何使用 python 快速计算从当月1日到今天(不含或含今日)之间的工作日天数,提供基于 numpy 的高效方案和纯 python 的兼容性方案,并附带代码示例与关键注意事项。
在金融、人力资源或任务调度等业务场景中,常需统计“本月已过多少个工作日”(例如用于考勤统计、SLA 计算或报表生成)。注意:标准定义中,“工作日”通常指周一至周五(weekday() 返回 0–4),不包含周末及法定节假日;本文默认仅排除周末,如需支持自定义节假日,需额外扩展。
✅ 推荐方案:使用 numpy.busday_count
numpy.busday_count() 是专为工作日计算设计的高性能函数,底层优化良好,且支持自定义周内工作日(如 weekmask='1111100')和节假日数组(holidays= 参数):
from datetime import datetime import numpy as np today = datetime.today().date() first_day = today.replace(day=1) # 注意:busday_count(start, end) 是左闭右开区间 → 包含 first_day,不包含 today # 因此若需包含今日,应将 end 设为 today + 1 天 n_business_days_excl_today = np.busday_count(first_day, today) # 输出:7(以 2024-02-12 为例) n_business_days_incl_today = np.busday_count(first_day, today + timedelta(days=1)) # 输出:8
⚠️ 关键提示:busday_count(start, end) 不包含 end 日期,因此统计“截至今日(含)”需将结束日期设为 today + timedelta(days=1)。
? 纯 Python 方案(无需 NumPy)
适用于轻量环境或无法安装 NumPy 的场景。利用 date.weekday() 判断是否为周一至周五(返回值 0–4),配合 timedelta 遍历逐日判断:
from datetime import datetime, timedelta
today = datetime.today().date()
first_day = today.replace(day=1)
delta_days = (today - first_day).days
# 统计 [first_day, today) 区间内的工作日(不含 today)
n_business_days = sum(
(first_day + timedelta(days=n)).weekday() < 5
for n in range(delta_days)
)
# 若需包含 today,则 range 改为 range(delta_days + 1)该方法逻辑清晰、可读性强,时间复杂度为 O(Δd),对单月计算(最多31次迭代)完全无性能压力。
? 注意事项与最佳实践
- 时区与日期对象类型:确保所有日期均为 date 类型(非 datetime),避免因时间部分引发意外行为;
- 节假日支持:numpy.busday_count 支持 holidays 参数(接受 array-like of datetime64),可传入国家/地区法定假日列表;
- 月末边界:date.replace(day=1) 在任何日期下均安全(如 2024-03-31.replace(day=1) → 2024-03-01),无需额外判断;
- 可复用封装建议:
def business_days_since_month_start(include_today: bool = False) -> int:
from datetime import datetime, timedelta
import numpy as np
today = datetime.today().date()
first = today.replace(day=1)
end = today + timedelta(days=1) if include_today else today
return int(np.busday_count(first, end))通过上述任一方法,均可准确、简洁地获取当月已过工作日数量,兼顾效率、可维护性与业务扩展性。










