
本文介绍如何借助 laravel 的 carbon 库,将指定月份中剔除周末(周六、周日)的工作日序列,按“以周一为起点、周五为终点”的逻辑划分为多个工作周区间,并支持起始/结束日不完整(如从周五开始)的边界情况处理。
本文介绍如何借助 laravel 的 carbon 库,将指定月份中剔除周末(周六、周日)的工作日序列,按“以周一为起点、周五为终点”的逻辑划分为多个工作周区间,并支持起始/结束日不完整(如从周五开始)的边界情况处理。
在实际业务场景中(如排班系统、工时统计、服务周期计算),我们常需将某个月份的所有工作日(即排除周六、周日后的日期集合)按“周”进行逻辑分组——但这里的“周”并非日历上的自然周(周一到周日),而是仅包含周一至周五的“工作周”,且需支持非整周起止(例如某月1号是周五,则第一周仅有1天;若28号是周四,则最后一周缺周五)。
Carbon 作为 PHP 中最成熟的日期处理库,提供了强大的日期操作与本地化能力,可优雅解决该问题。关键在于:不依赖 strtotime 字符串解析(易出错、难维护),而应使用 Carbon 的面向对象方法精确控制工作日范围与周切分逻辑。
✅ 推荐实现方案(Carbon 原生方式)
以下代码以 CarbonPeriod + 条件过滤为核心,生成清晰、可读、可复用的工作周分组:
use Carbon\Carbon;
use Carbon\CarbonPeriod;
// 假设目标月份为 2024-05(5月)
$monthStart = Carbon::create(2024, 5, 1)->startOfMonth();
$monthEnd = Carbon::create(2024, 5, 1)->endOfMonth();
// 获取该月所有工作日(周一至周五)
$workdays = CarbonPeriod::create($monthStart, $monthEnd)
->filter(fn(Carbon $date) => $date->isWeekday()) // 自动排除周末(isWeekday() = !isWeekend()
->toArray();
if (empty($workdays)) {
echo "No weekdays in this month.";
return;
}
// 按“工作周”分组:每组以周一为起点,最多含5天(但允许不完整)
$weeks = [];
$currentWeek = [];
foreach ($workdays as $date) {
// 若当前为空,或 date 是新周一,则开启新一周
if (empty($currentWeek) || $date->isMonday()) {
if (!empty($currentWeek)) {
$weeks[] = $currentWeek;
}
$currentWeek = [$date];
} else {
$currentWeek[] = $date;
}
}
// 添加最后一周
if (!empty($currentWeek)) {
$weeks[] = $currentWeek;
}
// 格式化输出每组区间(示例)
foreach ($weeks as $index => $weekDays) {
$first = $weekDays[0];
$last = $weekDays[count($weekDays) - 1];
$rangeLabel = sprintf(
'%s %d – %s %d, %d',
$first->format('M'),
$first->day,
$last->format('M'),
$last->day,
$last->year
);
echo "Week " . ($index + 1) . ": $rangeLabel\n";
// 可选:输出具体日期列表
// echo " Dates: " . implode(', ', array_map(fn($d) => $d->format('Y-m-d'), $weekDays)) . "\n";
}⚠️ 注意事项与最佳实践
-
避免硬编码
strtotime:原答案中使用strtotime("this week thursday -$i week")存在严重缺陷:它依赖服务器时区与当前周基准(如“this week”含义模糊),且无法适配任意起止月份,缺乏可移植性与可测试性。 -
isWeekday()是关键:Carbon 的isWeekday()方法等价于!$date->isWeekend(),自动识别周一至周五(不受 locale 影响),比手动判断dayOfWeek数值更安全。 - 边界鲁棒性:上述方案天然支持非整周场景(如首日为周五 → 第一周仅1天;末日为周四 → 最后一周仅4天),无需额外条件分支。
-
性能提示:若处理超长周期(如跨年工作日),建议结合数据库查询(如
WHERE WEEKDAY(date) BETWEEN 0 AND 4)预筛选,再交由 PHP 分组。
✅ 总结
将工作日按周划分,本质是对日期集合按业务规则(周一至周五)做有序分桶。Carbon 提供了语义清晰、链式调用、时区安全的 API,远优于原始 strtotime 方案。核心思路是:先提取工作日序列 → 再按周一触发分组 → 最后格式化输出。此模式可轻松扩展至自定义工作周(如含周六半日)、节假日排除等进阶需求。

















