首页 > 解决方案 > 如何检查日期期间同一天的时间段重叠?

问题描述

我为不同的用户组创建了班次。班次包括班次开始时间和结束时间,适用的星期几(多选)和日期期间(从日期到日期)。

特定用户的班次选择是多项选择,因为一个用户可以在同一天或不同时间在不同时间有多个班次。那么如何检查选定的班次是否与一个用户不能同时拥有两个班次的方式重叠?

我试过先检查,工作日是否相交,如果相交,然后检查日期和时间段是否重叠或不使用下面的代码,但没有得到正确的结果。

/**
 * @Route("/shift/checkTimeConflict", methods={"POST"})
 */
public function checkTimeConflict(Request $request)
{
    $data = $request->request->all();
    if (isset($data['shifts']) && count($data['shifts']) > 1) {
        $shifts = $this->getDoctrine()
            ->getRepository(Shift::class)
            ->findById($data['shifts']);
        foreach ($shifts as $key => $val) {
            $shift_data[$key]['id'] = $val->getId();
            $shift_data[$key]['title'] = $val->getTitle();
            $shift_data[$key]['weekday'] = $val->getWeekday();
            $shift_data[$key]['start_time'] = $val->getStartTime()->format('H:i');
            $shift_data[$key]['end_time'] = $val->getEndTime()->format('H:i');
            $shift_data[$key]['time_period_start'] = $val->getTimePeriodStart()->format('Y-m-d');
            $shift_data[$key]['time_period_end'] = $val->getTimePeriodEnd()->format('Y-m-d');
        }

        for ($i=0; $i < count($shift_data); $i++) { 
            if ($this->checkDateTimeOverlaps($shift_data[$i], $shift_data))
                return new JsonResponse(true);
        }
    }

    return new JsonResponse(false);
}

/**
 * Check provided shift time for the day and period overlaps with other shifts
 */
public function checkDateTimeOverlaps($shift, $shift_data)
{
    $start = strtotime($shift['time_period_start'].' '.$shift['start_time']);
    $end = strtotime($shift['time_period_end'].' '.$shift['end_time']);
    for ($i=0; $i < count($shift_data); $i++) {
        if ($shift['id'] != $shift_data[$i]['id']) {
            $check_start = strtotime($shift['time_period_start'].' '.$shift['start_time']);
            $check_end =  strtotime($shift['time_period_end'].' '.$shift['end_time']);
            if (!empty(array_intersect($shift['weekday'], $shift_data[$i]['weekday']))) {
                if (($start > $check_start && $start < $check_end) || ($end > $check_start && $end < $check_end) || ($check_start > $start && $check_start < $end) || ($check_end > $start && $check_end < $end)) {
                    return true; // intersects
                }
            }
        }
    }
    return false; // no conflict
}

例如,选定的班次具有以下数据:

(1) 09:00-13:00, Monday-Friday, 2019-01-01 - 2020-01-01, First-Half

(2) 14:00-18:00, Monday-Friday, 2019-01-01 - 2020-01-01, Second-Half

(3) 18:00-20:00, Monday-Friday, 2019-01-01 - 2020-01-01, Over-Time

(4) 09:00-14:00, Saturday, 2019-01-01 - 2020-01-01, Saturday Half Day

(5) 09:00-13:00, Monday-Friday, 2020-02-01 - 2021-02-28, Part-Time

上面应该没有冲突 [checkDateTimeOverlaps() 应该返回 false],因为同一天和日期期间没有时间交集。但是,如果我如下替换第 5 行:

(5) 09:00-13:00, Monday-Friday, 2019-01-01 - 2019-01-31, Part-Time

它应该返回冲突 [checkDateTimeOverlaps() 应该返回 true],因为一个人不能同时有两个班次。在上述情况下,第 1 行和第 5 行有一个交叉点。

标签: php

解决方案


推荐阅读