前段时间,产品同学在群里甩过来一句话:“需求评审定在下周三,开发排 15 个工作日,那上线日期是几号?”
我在脑子里数了数:15 个工作日,三周,那就是下下下周五呗。
结果真去排的时候才发现——中间夹着一个国庆假期。整整差了 9 天。
说实话,这种坑我踩过不止一次。算试用期、算合同交付日、算项目排期,只要涉及“工作日”,就特别容易翻车。今天就把这件事彻底讲清楚:工作日到底怎么算,有哪些坑,以及 Excel、代码、在线工具分别该怎么用。
📌 问题根源:为什么“工作日”这么难算
大部分人算工作日的方式是这样的:
15 个工作日 = 3 周 = 21 天
这个换算在真空环境里是对的,但在现实里,至少有四个变量会把它打乱。
坑 1:自然日 ≠ 工作日
这是最基础的一层。合同里写“30 日内交付”,如果没写明是自然日还是工作日,两边理解可能完全不一样。
- 自然日:连续计算,包含周末和节假日
- 工作日:只算上班的日子
同样是“30 天”,自然日是 30 天,工作日可能横跨 42 天。差出来的 12 天,就是纠纷的来源。
坑 2:周末不是唯一的非工作日
法定节假日要从工作日里扣掉。但麻烦的是:
- 每年的法定节假日都不一样
- 元旦、春节、清明、劳动节、端午、中秋、国庆,一共 7 类
- 春节和国庆经常连着放 7~8 天
如果你只用“排除周末”的公式,遇到长假就会高估工作日数量。
坑 3:调休补班——中国特有的反向操作
这是最容易被忽略的一点。
国内的放假安排里有调休:为了凑出长假,会把某个周六或周日调成上班日。也就是说:
⚠️ 有些周六周日是工作日,有些工作日是休息日。
任何默认“周六周日 = 休息”的工具,如果不单独处理调休补班日,算出来的结果一定是错的。
坑 4:边界条件——起始日算不算?
“10 个工作日之后是哪天”,这里的“之后”有两种理解。用一段没有节假日干扰的日期来看最清楚:
以“起始日 2026-06-10(周三),往后数 3 个工作日”为例:
| 不含起始日(主流) | 不计入 | 2026-06-15(周一) |
| 含起始日 | 算作第 1 天 | 2026-06-12(周五) |
Excel 的 WORKDAY 用的是不含起始日,NETWORKDAYS 则是首尾都含。同一个表里混用这两个函数,结果就会莫名其妙差一天。
🛠️ 三种解法对比:手算、Excel、代码、在线工具
先给结论,后面再逐个展开:
| 手掰日历 | 一周以内的粗略估算 | ❌ | ❌ | 极低 |
| Excel 公式 | 已有表格、需要批量 | ✅(手动维护) | ⚠️(需要技巧) | 中 |
| Python / JS | 系统集成、定时任务 | ✅ | ✅(用现成库) | 中高 |
| 在线工具 | 临时查一次、给别人发结论 | ✅(手动添加) | ⚠️(视工具而定) | 极低 |
📊 方案一:Excel 公式(最常用)
1. 算两个日期之间有多少个工作日
=NETWORKDAYS(A1, B1)
=NETWORKDAYS(A1, B1, 节假日区域)
- A1 起始日期,B1 结束日期
- 首尾两天都算在内
- 第三个参数是节假日列表(一个单元格区域,里面放所有法定假日日期)
举个例子:A1 = 2026-10-09,B1 = 2026-12-31
=NETWORKDAYS("2026-10-09", "2026-12-31")
结果是 60。也就是这 84 个自然日里,扣掉 24 个周末日,剩 60 个工作日。
2. 算 N 个工作日之后是哪天
=WORKDAY(A1, 20)
=WORKDAY(A1, 20, 节假日区域)
- 不含起始日,从第二天开始往后数
- 传负数就是往前推
=WORKDAY("2026-09-30", 20)
结果是 2026-10-28(周三)。
但这个结果其实是错的——它把国庆长假当成了正常工作日。补上节假日列表再算一次:
=WORKDAY("2026-09-30", 20, D1:D5)
其中 D1:D5 放国庆假期里的工作日:10-01、10-02、10-05、10-06、10-07(10-03 和 10-04 本来就是周六周日,不用重复排除)。
结果是 2026-11-04(周三)。日历上差了 7 天——国庆长假横跨的这 7 天里,有 5 天本来是工作日。
3. 自定义周末规则(单休、大小周)
=NETWORKDAYS.INTL(A1, B1, 11) ' 11 = 只把周日当休息日
=NETWORKDAYS.INTL(A1, B1, "0000011") ' 7 位字符串,周一到周日,1=休息
"0000011" 表示周一到周五上班、周六周日休息(默认规则);"0000010" 就是大小周里的那种“只休周日”。
4. 处理调休补班日的骚操作
NETWORKDAYS 没法单独把某个周六“捞回来”。常见的绕法是把补班日单独维护一张表,然后加回去:
=NETWORKDAYS.INTL(A1, B1, 1, 节假日表) + COUNTIFS(补班日表, ">="&A1, 补班日表, "<="&B1)
💡 提示:节假日表和补班日表都要每年手动更新一次。国务院一般在上一年的 11~12 月公布次年的放假安排,记得同步。
💻 方案二:代码实现(系统集成用)
Python:numpy 的 busday 系列
import numpy as np
# 注意:busday_count 的结束日期是「不包含」的
# 想统计 2026-10-09 ~ 2026-12-31,要传 2027-01-01
np.busday_count('2026-10-09', '2027-01-01')
# 60
# 加节假日
holidays = ['2026-10-01', '2026-10-02', '2026-10-05',
'2026-10-06', '2026-10-07']
np.busday_count('2026-09-30', '2026-11-01', holidays=holidays)
# 18
# N 个工作日之后
np.busday_offset('2026-09-30', 20, roll='forward')
# datetime.date(2026, 10, 28)
np.busday_offset('2026-09-30', 20, roll='forward', holidays=holidays)
# datetime.date(2026, 11, 4)
⚠️ 最大的坑:busday_count 的第二个参数是开区间,而 Excel 的 NETWORKDAYS 是闭区间。从 Excel 迁到 Python,忘了 +1 天,结果就会少算一天。
Python:直接用现成的中国节假日库
自己维护节假日表太累,可以直接用 chinesecalendar:
# pip install chinesecalendar
from datetime import date
from chinese_calendar import is_workday, get_workdays, find_workday
# 判断某天是否工作日(已内置调休数据)
is_workday(date(2026, 10, 1)) # False,法定假日
# 统计区间内的工作日,返回的是列表,取长度
# 注意:这里是闭区间,首尾两天都算,和 numpy 的开区间正好相反
len(get_workdays(date(2026, 10, 9), date(2026, 12, 31)))
# N 个工作日之后是哪天,等价于 Excel 的 WORKDAY(同样不含起始日)
find_workday(delta_days=20, date=date(2026, 9, 30))
它的优势是内置了调休数据:补班的周六会被正确识别成工作日,调休放掉的工作日也会被识别成休息日。你不用再自己维护节假日表和补班日表,is_workday 直接告诉你那天要不要上班。
❗ 注意:这类库的数据只覆盖到已公布放假安排的年份,超出范围会直接抛 NotImplementedError。上线前一定要检查数据覆盖范围,并在每年年底安排一次升级(pip install -U chinesecalendar)。
JavaScript:手写一个(无依赖)
function addWorkdays(start, n, holidays = new Set()) {
const d = new Date(start);
let count = 0;
while (count < n) {
d.setDate(d.getDate() + 1);
const day = d.getDay();
const iso = d.toISOString().slice(0, 10);
if (day !== 0 && day !== 6 && !holidays.has(iso)) count++;
}
return d;
}
function countWorkdays(start, end, holidays = new Set()) {
let n = 0;
const d = new Date(start);
while (d <= end) {
const day = d.getDay();
const iso = d.toISOString().slice(0, 10);
if (day !== 0 && day !== 6 && !holidays.has(iso)) n++;
d.setDate(d.getDate() + 1);
}
return n;
}
逻辑很直白:一天一天往后走,遇到周六周日和节假日就跳过。性能上完全够用——算 10 年也才 3600 多次循环。
🌐 方案三:在线工具(临时查一次最省事)
如果只是偶尔查一下、或者要把结果截图发到群里,装环境、开 Excel 都嫌麻烦。
我平时比较常用的是一个在线的工作日计算器:https://leowh.com/tools/workday/index.html https://leowh.com/tools/workday/index.html 
它主要提供三块功能:
1. 区间工作日统计
填起始日期和结束日期,一次给出四个数:总天数、工作日、周末天数、节假日天数。默认排除周六周日。
2. 自定义排除节假日
下面有个“排除节假日”的区域,可以手动添加日期,添加后变成标签,点 x 移除。国庆这种长假,就把放假的那几天一个个加进去。
3. 加工作日反推日期
填起始日期 + 要加的工作日数,它会自动跳过周末和已排除的节假日,直接算出结束日期。这个就是我开头那个场景要用的功能。
说下它的边界,避免误用:
- ⚠️ 法定节假日需要手动添加,它不内置中国节假日日历,也不会自动帮你处理调休补班
- ⚠️ 所以跨年度的长期排期,还是建议用带调休数据的代码方案
- ✅ 优点是纯前端、无需登录、即开即用,适合快速验证一个日期
同一站上还有周数查询和日期计算器,算 ISO 周数、算日期差值的时候可以顺手用。
🎯 三个实战场景对比
场景一:项目排期
需求:2026-10-09 启动,工期 60 个工作日,什么时候交付?
| 按自然日 | 10-09 + 60 天 | 2026-12-08 |
| 按工作日(只排周末) | WORKDAY 逻辑 | 2027-01-01 |
| 按工作日(含元旦假期) | 排除 2027-01-01 | 2027-01-04 |
结论:三种口径差了将近一个月。排期会上一定要明确说清楚用的是哪一种。
顺便说一句,纯按周末算出来的 2027-01-01 是元旦当天,这种“交付日撞法定节假日”的结果本身就是个明显的信号:你的计算漏了节假日。
场景二:合同交付期
需求:合同 2026-09-30 签订,约定“20 个工作日内交付”。
| ❌ 不排除 | 2026-10-28 | 把国庆长假也算成了工作日 |
| ✅ 排除 10/1–10/7 | 2026-11-04 | 实际口径 |
| ✅ 再排除调休补班 | 需按当年安排复核 | 补班的周六要算回工作日 |
结论:差了 7 天。如果按第一个日期签合同,乙方等于白拿一周;如果按第二个日期签而对方按第一个理解,就是违约风险。
场景三:考勤与假期核算
需求:统计 2026 年 Q3(6-1 到 8-31)的应出勤天数。
| 自然日总数 | 92 天 |
| 周末天数 | 26 天 |
| 工作日(未扣节假日) | 66 天 |
| 需额外扣除 | 端午假期中的工作日 |
结论:66 天是个上限,扣掉端午之后才是真实应出勤天数。做考勤基数的时候一定要扣,否则员工的日均工资会被算低。
🔴 什么情况下用哪种方案?
必须上代码的情况
🔴 排期跨越法定节假日,且需要精确到天 🔴 涉及调休补班(国内场景基本都涉及) 🔴 需要批量处理几百上千条日期 🔴 结果要写进系统、生成报表、自动发通知
Excel 就够的情况
🟡 已经有一份表格,加两列公式就行 🟡 节假日数量少,手动维护成本低 🟡 需要和业务方一起改参数、当场对数
在线工具最划算的情况
🟢 临时查一个日期,查完就扔 🟢 要把结果发给别人看,需要直观的界面 🟢 手边没有 Excel,或者在手机上 🟢 想快速验证一下自己手算的结果对不对
❓ 常见问题
Q:为什么我算的工作日总比 HR 少一天?
A:九成是边界口径问题。检查两点:起始日算不算(WORKDAY 不算,NETWORKDAYS 算),以及区间是开区间还是闭区间(numpy.busday_count 的结束日不含)。
Q:调休补班的周六到底要不要算工作日?
A:要算。国内调休的逻辑是“借周末凑长假”,被借走的那天要还回来。所有默认排除周六周日的公式和工具,都需要额外把补班日加回来。
Q:节假日列表哪里找?
A:以国务院办公厅每年发布的放假安排通知为准,一般在上一年的 11~12 月公布。代码场景建议直接用 chinesecalendar 这类库,省得手动维护。
Q:跨年计算有什么特别要注意的?
A:注意两件事。一是元旦(1 月 1 日)本身就是法定假日;二是很多节假日库的数据只覆盖到已公布安排的年份,跨到下一年可能直接失效。
Q:闰年会影响工作日计算吗?
A:会影响总天数,但不需要特殊处理。2024 年有 366 天、262 个工作日;2025 和 2026 年都是 365 天、261 个工作日。日期库内部已经处理好了,自己用天数做除法的时候才要小心。
✅ 总结
工作日计算看着简单,实际上是个“细节决定成败”的活。核心就四条:
✅ 先统一口径:自然日还是工作日,含不含起始日,白纸黑字写清楚 ✅ 别忘了节假日:只排周末的公式,遇到长假一定出错 ✅ 国内还要处理调休:补班的周六是工作日,这是最容易漏的一环 ✅ 按场景选工具:临时查用在线工具,做表用 Excel,进系统用代码
我自己踩过的最大的坑,就是拿“15 个工作日 = 3 周”这个直觉去排期,结果中间夹了个国庆。
算日期这件事,宁可多花两分钟验证,也别在合同和排期上赌。
🔗 相关链接
- 工作日计算器:https://leowh.com/tools/workday/index.html
- Excel NETWORKDAYS 函数文档:https://support.microsoft.com/office/networkdays-function-48e715bf-c7de-4f65-8641-9fad3b1b871c
- numpy.busday_count 文档:https://numpy.org/doc/stable/reference/generated/numpy.busday_count.html
- chinesecalendar(中国节假日库):https://github.com/LKI/chinese-calendar
