You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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号是周几,第一周都从1号开始,到当月第一个周六结束(若周六超出当月则用月末),确保月初日期不被遗漏
  2. 后续周按周一至周六生成:统一周的起始和结束规则,符合预期输出格式
  3. 处理月末剩余日期:如果最后一个周六后还有未覆盖的日期,自动补充为最后一周
  4. 移除强制修改逻辑:取消原代码中强制修改最后一周结束日期的操作,让日期逻辑自然生成

测试验证

调用函数测试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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:04:55