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

PHP无重叠可用时间段检测功能异常,请求排查

PHP时间段重叠检测失效:已存在的预约未被识别

问题场景

我编写了代码用于查找指定日期、员工的无重叠可用时间段,逻辑上应检测到重叠预约,但实际运行出现错误:当检测11:00-12:00的时间段时,数据库中明确存在10:30-11:30的预约,程序却返回count=0,未识别到重叠。

相关代码

主检测函数

function detect_not_overlap($date, $worker_id, $duration) {
    $available_slots = [];

    $start_time = strtotime('09:00:00');
    $end_time = strtotime('17:00:00');

    while ($start_time <= $end_time - $duration * 3600) {
        $start = date('H:i:s', $start_time);
        $start_timestamp = strtotime($start);
    
        $end = date('H:i:s', $start_time + $duration * 3600);
        $end_timestamp = strtotime($end);
        
        $db = new DatabaseManager();
        $apDAO = new AppointmentDAO($db);
        $count_existing_slots = $apDAO->getOverlappedCount($start_timestamp,$end_timestamp, $date, $worker_id);
        if ($count_existing_slots == 0 || $count_existing_slots == null) {
            $available_slots[] = date('H:i:s', $start_time);
    
        }

        $start_time += 30 * 60;
        //$start_time = strtotime('+30 minutes', $start_time);
    }

    return $available_slots;
}

数据库查询函数

public function getOverlappedCount($start_time, $end_time, $date, $worker_id) {
    try {
        $stmt = $this->db->getConnection()->prepare("SELECT count(*) FROM appointment WHERE end_time > :start_time AND start_time < :end_time AND date = :date AND worker_id = :worker_id");
        $stmt->bindValue(":start_time", $start_time);
        $stmt->bindValue(":end_time", $end_time);
        $stmt->bindValue(":date", $date);
        $stmt->bindValue(":worker_id", $worker_id);
        $stmt->execute();
        $count = $stmt->fetchColumn();
        return $count;
    } catch(PDOException $e) {
        return false;
    } finally {
        $this->db->closeConnection();
    }
}

问题根源排查

1. 时间戳生成错误(核心原因)

主函数中$start_timestamp = strtotime($start);的逻辑存在致命问题:

  • $start是仅含时分秒的字符串(如11:00:00),strtotime解析时会默认使用当前系统日期生成时间戳,而非传入的$date参数。
  • 数据库中存储的预约时间是对应$date的(如2024-05-20 10:30:00),而程序传入查询的时间戳是当前日期的11:00,两者不属于同一天,自然无法匹配到重叠记录。

2. 数据库连接重复创建(性能问题)

每次循环都实例化DatabaseManager和AppointmentDAO并关闭连接,会导致大量不必要的资源开销,虽然不是当前问题的直接原因,但必须优化。

修复方案

方案1:修正时间戳生成逻辑

将传入的$date与时间字符串拼接后生成正确的时间戳,确保与数据库中的日期一致:

function detect_not_overlap($date, $worker_id, $duration) {
    $available_slots = [];

    $start_time = strtotime('09:00:00');
    $end_time = strtotime('17:00:00');
    
    // 提前初始化数据库连接(优化性能)
    $db = new DatabaseManager();
    $apDAO = new AppointmentDAO($db);
    // 生成目标日期的0点时间戳,用于后续计算
    $target_date_timestamp = strtotime($date . ' 00:00:00');

    while ($start_time <= $end_time - $duration * 3600) {
        $start = date('H:i:s', $start_time);
        // 生成带目标日期的完整时间戳
        $start_timestamp = $target_date_timestamp + ($start_time - strtotime('00:00:00'));
    
        $end = date('H:i:s', $start_time + $duration * 3600);
        $end_timestamp = $target_date_timestamp + ($start_time + $duration * 3600 - strtotime('00:00:00'));
        
        $count_existing_slots = $apDAO->getOverlappedCount($start_timestamp,$end_timestamp, $date, $worker_id);
        if ($count_existing_slots == 0 || $count_existing_slots == null) {
            $available_slots[] = $start;
        }

        $start_time += 30 * 60;
    }
    
    // 循环结束后统一关闭连接
    $db->closeConnection();
    return $available_slots;
}

方案2:确认数据库字段类型匹配

  • 如果数据库中start_time和end_time存储的是完整datetime字符串,需确保传入的时间戳转换为对应格式后再绑定(或直接使用datetime字符串拼接)。
  • 如果存储的是当天的秒数(如10:30对应37800),则需将计算后的完整时间戳转换为当天秒数:$start_seconds = $start_timestamp - $target_date_timestamp;,再传入查询。

可选:优化SQL边界条件

若需要严格禁止首尾相接的预约(如11:30结束的预约,11:30不能开始新预约),可将SQL条件修改为:

SELECT count(*) FROM appointment 
WHERE end_time >= :start_time 
  AND start_time <= :end_time 
  AND date = :date 
  AND worker_id = :worker_id

内容的提问来源于stack exchange,提问作者Galaxylokka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 04:27:48