datetime循环校验是php7原生环境下最稳妥的工作日计数方式:不依赖第三方库,逻辑透明,支持单休/轮休配置,需用format('w')判断星期(0=周日),起止日均包含,避免diff()->days误用。

DateTime 类配合循环校验是 PHP7 中最可控、最不易出错的工作日计数方式。硬编码模 7 或依赖 diffInWeekdays()(Carbon 特有)在 PHP7 原生环境中不可用,且默认排除周六/周日的逻辑无法适配单休、轮休等真实业务。
用 DateTime 循环遍历 + 显式判断星期几
这是 PHP7 原生环境下最稳妥的做法:不依赖第三方库,逻辑透明,边界清晰。
- 必须用
$date->format('w')获取星期索引(0=周日,1=周一…6=周六),不能用'N'(ISO 标准,1=周一),避免混淆 - 起止日期都需包含在内,所以循环条件是
$current ,且每次迭代后调用 <code>modify('+1 day')前先检查 - 避免在循环中反复修改原
DateTime对象导致引用污染——每次用clone或copy() - 若需排除节假日,只需在判断中增加
in_array($current->format('Y-m-d'), $holidays)
示例片段:
$start = new DateTime('2026-09-01');
$end = new DateTime('2026-09-15');
$holidays = ['2026-09-10']; // 示例节假日
$workdays = 0;
$current = clone $start;
while ($current format('w');
$dateStr = $current->format('Y-m-d');
if (!in_array($w, [0, 6]) && !in_array($dateStr, $holidays)) {
$workdays++;
}
$current->modify('+1 day');
}
echo $workdays; // 输出:11(含 9 月 10 日中秋?需按实际节假日表校准)
别踩 DateTime::diff()->days 的坑
diff() 返回的是自然日差值,不是工作日。直接拿 $interval->days 当工作日用,等于没算。
-
$start->diff($end)->days只是总天数(如 2026-09-01 到 2026-09-15 是 14 天),和工作日完全无关 - 有人试图用
floor($interval->days * 5 / 7)估算,但遇到跨月、边界落在周末、节假日集中等情况误差极大 - 尤其当起始日是周日、结束日是周六时,这种估算会系统性少算 1 天
自定义工作日配置(如单休、周三休息)
把「哪些天算工作日」从硬编码改成可配置,只需改一个数组判断:
- 定义
$workdaysOfWeek = [1,2,3,4,5,6]表示周一至周六上班(单休) - 或
$workdaysOfWeek = [1,3,5]表示只上 Mon/Wed/Fri(弹性制) - 判断条件改为:
in_array($w, $workdaysOfWeek),不再写死!= 0 && != 6 - 注意:PHP 的
format('w')周日是 0,所以数组里不要写 0,除非你真把周日设为工作日
性能敏感时怎么优化
如果要计算跨度几年、上万天的区间,纯循环会变慢。这时可分段处理:
- 先算完整周数:
floor($totalDays / 7) * count($workdaysOfWeek) - 再单独处理剩余不足一周的日期(最多 6 天),逐日判断
- 关键点:起始日对齐到周一(用
modify('this Monday')),否则首尾残段容易漏算或重算 - 该优化仅在天数 > 1000 时值得投入;日常请假、排班等场景,直接循环更安全、更易 debug
真正难的不是写代码,而是确认「哪几天算工作日」——这个规则必须来自业务方,而不是开发者拍脑袋。节假日列表、调休安排、地区差异,这些都得落地成明确的 $holidays 数组或数据库查询,否则任何算法都是空中楼阁。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











