PHP动态生成每月周列表bug修复:2023年11月周起始异常
修复PHP月度周列表生成函数的Bug
我编写了一个用于动态生成每月周列表的PHP函数,但存在Bug。测试2023年11月时,生成的第一周为6日-11日,但实际第一周应为1日-4日。
原代码
function getListWeekPerMonth($tahun, $bulan){ $week_array = []; $count_week = 1; $start_date = date("Y-m-d", strtotime("$tahun-$bulan-1")); //$end_date = date("Y-m-d", strtotime("$tahun-$bulan-t")); if (date("N", strtotime($start_date)) == 6) { // 如果1号是周六,第一周设为1-8日 $end_date = date("Y-m-d", strtotime($start_date . " + 7 days")); // 第一周结束于8日 $week_array[] = [ 'week_number' => $count_week, 'start_date' => $start_date, 'end_date' => $end_date, 'start' => date("d", strtotime($start_date)), 'end' => date("d", strtotime($end_date)), ]; $count_week++; $start_date = date("Y-m-d", strtotime($end_date . " + 1 day")); } while (date("m", strtotime($start_date)) == $bulan) { // 检查是否为周一 if (date("N", strtotime($start_date)) == 1) { $end_date = date("Y-m-d", strtotime($start_date . " + 5 days")); // 周一直到周六 if (date("m", strtotime($end_date)) != $bulan) { $end_date = date("Y-m-d", strtotime("$tahun-$bulan-t")); } $week_array[] = [ 'week_number' => $count_week, 'start_date' => $start_date, 'end_date' => $end_date, 'start' => date("d", strtotime($start_date)), 'end' => date("d", strtotime($end_date)), ]; $start_date = date("Y-m-d", strtotime($end_date . " + 1 day")); $count_week++; } else { // 如果不是周一,跳转到下一个周一 $start_date = date("Y-m-d", strtotime($start_date . " + 1 day")); while (date("N", strtotime($start_date)) != 1) { $start_date = date("Y-m-d", strtotime($start_date . " + 1 day")); } } } // 强制修改最后一周的结束日期为月末 $week_array[count($week_array) - 1]['end_date'] = date("Y-m-t", strtotime("$tahun-$bulan")); $week_array[count($week_array) - 1]['end'] = date("t", strtotime("$tahun-$bulan")); return $week_array; }
预期输出(2023年11月)
Week 1 [01 - 04] Week 2 [06 - 11] Week 3 [13 - 18] Week 4 [20 - 25] Week 5 [27 - 30]
问题分析
原代码的核心问题:
- 仅处理了1号为周六的特殊情况,忽略了其他非周一的起始日(如2023年11月1日是周三)
- 当起始日不是周一或周六时,直接跳转到下一个周一,完全跳过了月初到第一个周一之间的日期,导致第一周缺失
- 最后强制修改最后一周的结束日期,可能覆盖正确的周结束逻辑
修复后的代码
function getListWeekPerMonth($tahun, $bulan){ $week_array = []; $count_week = 1; $current_date = date("Y-m-d", strtotime("$tahun-$bulan-1")); $month_end = date("Y-m-t", strtotime("$tahun-$bulan")); // 处理第一周:从1号到当月第一个周六,若周六超出当月则用月末日期 $first_saturday = date("Y-m-d", strtotime("$current_date next Saturday")); $first_week_end = strtotime($first_saturday) > strtotime($month_end) ? $month_end : $first_saturday; $week_array[] = [ 'week_number' => $count_week, 'start_date' => $current_date, 'end_date' => $first_week_end, 'start' => date("d", strtotime($current_date)), 'end' => date("d", strtotime($first_week_end)), ]; $count_week++; // 下一周从第一个周六的下周一开始 $current_date = date("Y-m-d", strtotime("$first_week_end next Monday")); // 处理后续完整周(周一至周六) while (strtotime($current_date) <= strtotime($month_end)) { $week_end = date("Y-m-d", strtotime("$current_date + 5 days")); // 周一+5天=周六 if (strtotime($week_end) > strtotime($month_end)) { $week_end = $month_end; } $week_array[] = [ 'week_number' => $count_week, 'start_date' => $current_date, 'end_date' => $week_end, 'start' => date("d", strtotime($current_date)), 'end' => date("d", strtotime($week_end)), ]; $count_week++; // 跳转至下周一 $current_date = date("Y-m-d", strtotime("$week_end next Monday")); } // 处理月末剩余日期(若最后一个周六后仍有日期) $last_week_start = date("Y-m-d", strtotime("$week_end + 1 day")); if (strtotime($last_week_start) <= strtotime($month_end)) { $week_array[] = [ 'week_number' => $count_week, 'start_date' => $last_week_start, 'end_date' => $month_end, 'start' => date("d", strtotime($last_week_start)), 'end' => date("d", strtotime($month_end)), ]; } return $week_array; }
修复说明
- 优先处理第一周:无论1号是周几,第一周都从1号开始,到当月第一个周六结束(若周六超出当月则用月末),确保月初日期不被遗漏
- 后续周按周一至周六生成:统一周的起始和结束规则,符合预期输出格式
- 处理月末剩余日期:如果最后一个周六后还有未覆盖的日期,自动补充为最后一周
- 移除强制修改逻辑:取消原代码中强制修改最后一周结束日期的操作,让日期逻辑自然生成
测试验证
调用函数测试2023年11月:
$weeks = getListWeekPerMonth(2023, 11); foreach ($weeks as $week) { echo "Week {$week['week_number']} [{$week['start']} - {$week['end']}]\n"; }
输出结果与预期完全一致:
Week 1 [01 - 04] Week 2 [06 - 11] Week 3 [13 - 18] Week 4 [20 - 25] Week 5 [27 - 30]
内容的提问来源于stack exchange,提问作者Muyana
相关产品推荐
相关产品推荐

