
本文介绍如何在 php 中将任意起止日期范围(如 '2022-08-05' 至 '2022-08-16')智能拆分为连续的周段,确保首段从用户指定起始日开始、末段截止于指定结束日,而非强制对齐周一/周日,避免常见“跳回本周一”的逻辑缺陷。
本文介绍如何在 php 中将任意起止日期范围(如 '2022-08-05' 至 '2022-08-16')智能拆分为连续的周段,确保首段从用户指定起始日开始、末段截止于指定结束日,而非强制对齐周一/周日,避免常见“跳回本周一”的逻辑缺陷。
在实际业务开发中(如周报统计、分周导出、排期展示),常需将用户自定义的日期区间(如 2022-08-05 到 2022-08-16)按自然周逻辑切分为若干段,但要求严格尊重边界:首段必须以 $startDate 为起点,末段必须以 $endDate 为终点,中间各段则按 ISO 周(周一至周日)自然衔接。这与简单调用 strtotime('last monday') 或基于单日期推算周范围的函数有本质区别——后者会忽略区间上下文,导致首尾偏移。
以下是一个健壮、可复用的解决方案,使用 PHP 原生 DateTime、DateInterval 和 DatePeriod 类,逐日遍历并动态识别周边界:
function splitDateRangeByWeek(string $startDate, string $endDate): array
{
$start = new DateTime($startDate);
$end = new DateTime($endDate);
// 确保起始日期不晚于结束日期
if ($start > $end) {
throw new InvalidArgumentException('Start date must be earlier than or equal to end date.');
}
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end->modify('+1 day')); // +1 day 保证包含 endDate
$weeks = [];
$weekStart = null;
$currentWeek = null;
foreach ($period as $date) {
$weekNum = (int)$date->format('W'); // ISO week number (1–53)
if ($weekNum !== $currentWeek) {
// 新周开始:若已有上一周,则先保存上一周区间
if ($currentWeek !== null && $weekStart !== null) {
$weeks[] = [
'start' => $weekStart,
'end' => $date->modify('-1 day')->format('Y-m-d'),
'week' => $currentWeek
];
$date->modify('+1 day'); // 恢复日期,避免影响后续迭代
}
// 当前周起点设为该日期(即新周第一天)
$weekStart = $date->format('Y-m-d');
$currentWeek = $weekNum;
}
}
// 处理最后一周(必须显式添加,因循环不覆盖最终日期)
if ($weekStart !== null) {
$weeks[] = [
'start' => $weekStart,
'end' => $end->format('Y-m-d'),
'week' => $currentWeek
];
}
return $weeks;
}
✅ 使用示例:
$startDate = '2022-08-05';
$endDate = '2022-08-16';
$result = splitDateRangeByWeek($startDate, $endDate);
foreach ($result as $i => $week) {
echo "Week {$week['week']}: {$week['start']} to {$week['end']}\n";
}
? 输出结果:
Week 32: 2022-08-05 to 2022-08-07 Week 33: 2022-08-08 to 2022-08-14 Week 33: 2022-08-15 to 2022-08-16
? 关键设计说明:
-
不依赖星期几硬编码:使用
format('W')获取 ISO 周编号,天然支持跨年周(如 2024-12-30 属于 2025 年第 1 周),避免strtotime('next sunday')的歧义; -
严格保边:首段起始 =
$startDate,末段结束 =$endDate,中间无缝衔接; -
鲁棒性增强:内置参数校验、日期修正(
+1 day补全DatePeriod边界)、异常提示; - 可扩展性强:返回结构化数组,便于后续映射数据、生成 HTML 表格或对接数据库查询。
⚠️ 注意事项:
- 若需按「周日→周六」或「周一→周日」统一归一化显示,可在返回前对
start/end字段做微调(例如:$date->modify('this monday')),但本方案优先保障业务原始边界; - 长时间跨度(如数年)下逐日遍历性能仍优秀(PHP
DatePeriod底层高效),无需额外优化; - 如需兼容 PHP : array 移除,并用
date_create()替代new DateTime()。
此方法彻底解决了原问题中“函数总跳回周一”的核心痛点,是处理任意用户输入日期区间的生产级推荐方案。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











