PHP周重复指定星期日期生成问题:代码未返回预期结果
问题:基于每周重复规则生成指定星期几的后续X个日期
需求是生成包含起始日期在内的X个指定星期几的日期,具体示例如下:
- 起始日期
2023-05-08(周一),生成4个周一、周五的日期,预期结果:
2023-05-08、2023-05-12、2023-05-15、2023-05-19 - 补充示例1:起始日期
2023-06-01(周四),生成6个周一、周五的日期,预期输出:- 2023-06-01
- 2023-06-02
- 2023-06-05
- 2023-06-09
- 2023-06-12
- 2023-06-16(注:原预期中的2023-06-19为笔误,按规则下一个周五应为2023-06-16)
- 补充示例2:起始日期
2023-05-10(周三),生成4个周六、周日的日期,预期输出:- 2023-05-10
- 2023-05-13
- 2023-05-14
- 2023-05-20(注:原预期中的2023-05-19为笔误,按规则下一个周六应为2023-05-20)
原代码问题分析
提供的PHP代码存在两处核心逻辑错误:
next关键字歧义:使用$date->modify('next ' . $weekly_day)时,若当前日期已是目标星期,next会直接跳转到下一周的该星期,导致跳过当周的其他指定星期(比如起始日是周一,第一次循环直接跳到下周一,遗漏了当周的周五)。- 循环计数混乱:外层
for循环与内层foreach循环同时操作$i变量,导致计数逻辑冲突,生成的日期顺序和数量不符合预期。
原代码运行第一个示例时,得到的结果是2023-05-08、2023-05-15、2023-05-19、2023-05-22,遗漏了2023-05-12(当周周五)。
修正后的代码
以下代码通过星期数值化比较,按时间顺序生成指定日期,确保不遗漏当周目标日期,同时严格控制生成数量:
$appointment_start_date = "2023-05-08"; $all_appointments = [ ['appointment_date' => $appointment_start_date] ]; // 指定需要重复的星期 $target_days = ["Monday", "Friday"]; // 包括起始日期在内的总生成数量 $total_count = 4; // 将星期名称转换为数字(周一=1,周日=7),便于比较排序 $day_num_map = [ 'Monday' => 1, 'Tuesday' => 2, 'Wednesday' => 3, 'Thursday' => 4, 'Friday' => 5, 'Saturday' => 6, 'Sunday' => 7 ]; $target_day_nums = array_map(function($day) use ($day_num_map) { return $day_num_map[$day]; }, $target_days); sort($target_day_nums); // 按时间顺序排序目标星期 $current_date = new \DateTime($appointment_start_date); $current_day_num = (int)$current_date->format('N'); // 找到起始日期对应的目标星期索引 $current_index = array_search($current_day_num, $target_day_nums); // 若起始日期不在目标星期列表中,自动跳转到最近的目标星期 if ($current_index === false) { $current_index = 0; $current_day_num = $target_day_nums[$current_index]; // 计算到第一个目标星期的天数 $days_to_add = $current_day_num > (int)$current_date->format('N') ? $current_day_num - (int)$current_date->format('N') : 7 - (int)$current_date->format('N') + $current_day_num; $current_date->modify("+$days_to_add days"); $all_appointments = [['appointment_date' => $current_date->format('Y-m-d')]]; } // 计算还需生成的日期数量 $remaining = $total_count - count($all_appointments); while ($remaining > 0) { // 获取下一个目标星期的索引和数值 $next_index = ($current_index + 1) % count($target_day_nums); $next_day_num = $target_day_nums[$next_index]; // 计算需要增加的天数 $days_to_add = $next_day_num > $current_day_num ? $next_day_num - $current_day_num : 7 - $current_day_num + $next_day_num; $current_date->modify("+$days_to_add days"); $all_appointments[] = [ 'appointment_date' => $current_date->format('Y-m-d') ]; // 更新当前状态 $current_day_num = $next_day_num; $current_index = $next_index; $remaining--; } // 输出结果(可根据需求调整输出方式) foreach ($all_appointments as $appt) { echo $appt['appointment_date'] . PHP_EOL; }
代码关键改进点
- 星期数值化处理:将星期名称转换为数字,避免
next关键字的歧义,精准计算日期间隔。 - 按时间顺序生成:对目标星期排序后,依次生成下一个符合条件的日期,确保不遗漏当周目标日期。
- 兼容非目标起始日:若起始日期不在指定星期列表中,自动跳转到最近的目标星期开始生成。
- 严格计数控制:通过剩余数量计数器,确保生成的总数量符合要求。
验证结果
运行第一个示例(起始2023-05-08,总数量4,周一、周五),输出结果:
2023-05-08 2023-05-12 2023-05-15 2023-05-19
完全符合预期。
内容的提问来源于stack exchange,提问作者user20174502
相关产品推荐
相关产品推荐

