最简单方法是用 date('N', $timestamp) 判断星期几(1=周一,7=周日),跳过6和7;避免用 date('w') 或字符串比较,起始时间需统一转时间戳,ThinkPHP5.1 无内置工作日迭代器,whereTime() 不支持直接筛工作日。

PHP 原生循环中跳过周末最简单的方法
直接用 date('N', $timestamp) 判断星期几(1=周一,7=周日),避开 6 和 7 即可。ThinkPHP5.1 本身不提供“工作日迭代器”,得靠自己控制循环逻辑。
常见错误是用 date('w')(0=周日),结果把周日当成 0、周六当成 6,一不小心就把周日当工作日了——尤其容易在跨月或跨年边界出错。
-
date('N')更安全:返回 1~7,且严格按 ISO-8601,周一始终是 1 - 别用字符串比较(如
date('D') === 'Mon'),受 locale 影响,本地化环境可能返回中文或其它语言缩写 - 起始时间必须用
strtotime()或DateTime统一转成时间戳,避免日期字符串隐式转换出错
ThinkPHP5.1 的 Db::name()->whereTime() 不能直接筛工作日
whereTime() 只支持 BETWEEN、>=、 等基础时间范围,不支持函数式条件(比如 <code>WEEKDAY() 或 DAYOFWEEK()),强行写 whereRaw('WEEKDAY(create_time) 虽然能用,但要注意 MySQL 版本兼容性:
- MySQL 5.7+ 支持
WEEKDAY()(0=周一),但低版本可能不支持 - 如果用
DAYOFWEEK()(1=周日),逻辑要反过来:只取 2~6(对应周一到周五) - 数据库层过滤虽省 PHP 循环,但无法替代 PHP 侧的日期生成逻辑——比如你要生成未来 30 个工作日列表,DB 没法“生成”,只能“筛选已有记录”
封装一个可靠的工作日日期生成器
别反复手写 while + if,抽成函数更稳。注意两个关键点:节假日不处理(那是业务逻辑),只保底排除周六日;且必须支持跨月/跨年自动递进。
立即学习“PHP免费学习笔记(深入)”;
function getWorkdays($start, $end, $format = 'Y-m-d') {
$dates = [];
$ts = strtotime($start);
$endTs = strtotime($end);
while ($ts <= $endTs) {
if (date('N', $ts) < 6) { // 1~5 是工作日
$dates[] = date($format, $ts);
}
$ts += 86400; // 每次加一天,不跳过,靠判断过滤
}
return $dates;
}
调用示例:getWorkdays('2024-04-01', '2024-04-10') 返回 8 个日期(去掉 4月6日、4月7日)。别用 DateTime::modify('+1 day') 链式调用,某些 PHP 版本在月末会有跳日 bug。
两个日期循环嵌套时怎么避免重复计算周末
如果你真在写双重循环(比如外层遍历月份,内层遍历该月所有天),最容易犯的错是:内层没重置起止时间,或外层用 date('t') 获取天数后硬写 for ($i=1; $i,导致日期拼接出错(如 <code>"2024-02-30" 被 PHP 自动转成 3月1日,然后你又对这个错位日期判 weekday)。
- 统一用时间戳推进,不用字符串拼接日期
- 外层循环用
DateTime控制月初/月末,内层用$date->modify('+1 day')但必须配合$date->format('Y-m-d')校验是否仍在当月 - 更稳妥的做法:先用单层循环生成完整工作日数组,再按需分组——双重循环在这里纯属过早优化,反而增加出错概率
真正难的不是跳过周末,而是后续要叠加法定节假日排除逻辑。那个得查表或调 API,和“工作日”不是同一维度的事——先跑通纯周一到周五再说。



















