使用Carbon PHP计算日期时如何正确跳过连续节假日
问题分析
原代码的核心问题有两个:
- 循环次数被固定为
$count,遇到多个连续节假日时,没法额外增加跳过次数 - 检查的是原始日期加上
$i个工作日后的日期,不是当前计算过程中已经调整过的日期,逻辑完全错位,导致新增的节假日没被检测到
比如你测试的场景:2023-06-16(周五)加1个工作日本来是6-19(周一),但6-19和6-20都是节假日,原代码只循环1次,只检查了6-19,加了一天到6-20,但没继续检查6-20是不是节假日,所以停在了错误的日期。
修正方案
换一种更可靠的思路:逐步推进日期,每一步都确认当前日期是有效工作日(非周末+非节假日),直到累计完成$count个有效工作日的添加。
修正后的代码:
function daySkip($date, $count = 0) { $holidays = ["2023-06-19", "2023-06-20"]; // 将节假日转为键为日期的关联数组,提升查询效率 $holidayMap = collect($holidays)->flip(); $currentDate = Carbon::parse($date); $validWorkdaysAdded = 0; while ($validWorkdaysAdded < $count) { $currentDate->addDay(); // 跳过周末和节假日,不计入有效工作日 if ($currentDate->isWeekend() || isset($holidayMap[$currentDate->toDateString()])) { continue; } $validWorkdaysAdded++; } return $currentDate->format("d-m-Y"); }
代码说明
- 用
collect($holidays)->flip()转换数组,把日期作为键,后续用isset查询比in_array效率更高,节假日数量多的时候差异更明显 - 循环逻辑改为:每次推进一天,只有当天是非周末且非节假日时,才算完成一个有效工作日的计数
- 不管有多少连续节假日,都会持续跳过,直到凑够
$count个有效工作日
测试你的场景:
$input = "2023-06-16"; $addday = daySkip($input, 1); // 输出 21-06-2023,符合预期
如果你偏好先加工作日再调整的思路,也可以用下面的写法,核心是循环检查当前日期是否在节假日列表中,直到跳出所有节假日:
function daySkip($date, $count = 0) { $holidays = ["2023-06-19", "2023-06-20"]; $holidayMap = collect($holidays)->flip(); $currentDate = Carbon::parse($date)->addWeekdays($count); // 循环跳过所有连续的节假日(同时自动跳过周末) while (isset($holidayMap[$currentDate->toDateString()]) || $currentDate->isWeekend()) { $currentDate->addDay(); } return $currentDate->format("d-m-Y"); }
内容的提问来源于stack exchange,提问作者Bertho Joris
相关产品推荐
相关产品推荐

