PHP计算可用预约时段代码遇非15分钟整时间结果错误如何解决
问题根因
原代码的已预约时段排除逻辑存在缺陷:仅会移除完全被已预约区间包裹的15分钟时段,当已预约结束/开始时间不是15分钟整数倍时,和预约区间存在部分重叠的可用时段会被误保留。
例如测试用例中15:30-16:10的已预约,16:00-16:15的时段和预约重叠了10分钟,但不符合时段开始≥预约开始 且 时段结束≤预约结束的条件,因此未被移除,最终返回错误的可用时段。
修复方法
将排除逻辑替换为通用的时间区间重叠判断:只要15分钟时段和任意已预约区间存在重叠,就从可用时段中移除。
重叠判断的核心逻辑为:时段开始时间 < 预约结束时间 且 时段结束时间 > 预约开始时间,覆盖所有部分重叠、完全包含的场景。
优化后完整代码
<?php $businessHours = [ ['09:00:00', '13:00:00'], ['14:00:00', '18:00:00'] // 1小时午休 ]; $appointments = [ ['10:00:00', '10:30:00'], // 格式为[开始时间, 结束时间] ['15:30:00', '16:10:00'] ]; $interval = 15 * 60; // 预约间隔,可根据服务时长动态调整 $result = []; // 先生成所有营业时间段内的间隔时段 foreach ($businessHours as $businessHour) { $periodStart = strtotime($businessHour[0]); $periodEnd = strtotime($businessHour[1]); $current = $periodStart; while ($current < $periodEnd) { $slotEnd = $current + $interval; // 避免跨营业时段的无效slot if ($slotEnd > $periodEnd) break; $result[] = [ 'start' => $current, 'end' => $slotEnd, 'start_str' => date('H:i:s', $current), 'end_str' => date('H:i:s', $slotEnd) ]; $current = $slotEnd; } } // 排除和已有预约重叠的时段 foreach ($appointments as $appointment) { $aptStart = strtotime($appointment[0]); $aptEnd = strtotime($appointment[1]); foreach ($result as $k => $slot) { // 时间重叠判断,覆盖所有重叠场景 if ($slot['start'] < $aptEnd && $slot['end'] > $aptStart) { unset($result[$k]); } } } // 输出时可按需取字符串格式 print_r(array_column($result, 'start_str', 'end_str')); ?>
额外优化点
- 提前将所有时间转换为时间戳存储,避免循环中重复调用
strtotime转换字符串,性能更高 - 新增了跨营业时段的slot过滤逻辑,避免出现超过营业结束时间的无效时段
- 同时保留时间戳和格式化字符串,后续业务使用更灵活
内容的提问来源于stack exchange,提问作者Jeroen
相关产品推荐
相关产品推荐

