Проверьте, не пересекаются ли два раза

Я хочу посмотреть, совпадает ли время, которое я читаю из БД, со временем, предоставленным пользователем.

Моя база данных выглядит так:

-----------------------------------------------
|organiser|meeting_start|meeting_end|boardroom|
-----------------------------------------------
| John Doe| 1340193600  | 1340195400| big     |
-----------------------------------------------

Мой код выглядит так:

date_default_timezone_set('Africa/Johannesburg');
$from = strtotime($_GET['meeting_date'] . ' ' . $_GET['meeting_start']);
$to = strtotime($_GET['meeting_date'] . ' ' . $_GET['meeting_end']);
$another_meeting = false;
$meeting_date = strtotime($_GET['meeting_date']);
$meeting_next = $meeting_date + 86400;

$result = mysql_query("SELECT meeting_start, meeting_end FROM admin_boardroom_booking WHERE boardroom = '" . $_GET['boardroom'] . "' AND meeting_start >= '" . $meeting_date . "' AND meeting_end < '" . $meeting_next . "'")or die(mysql_error());
while($row = mysql_fetch_array($result)) {
    $from_compare = $row['meeting_start'];
    $to_compare = $row['meeting_end'];

    $intersect = min($to, $to_compare) - max($from, $from_compare);
    if ( $intersect < 0 )
        $intersect = 0;

    $overlap = $intersect / 3600;
    if ( $overlap <= 0 ) {
        $another_meeting = true;
        break;
    }
}

if ($another_meeting)
    echo 'ERROR';

Если я намеренно наберу два перекрывающихся времени, это не выдаст ошибку. Что я делаю не так?


person Bird87 ZA    schedule 19.06.2012    source источник
comment
Ваш код уязвим для SQL-инъекций. Пожалуйста прочитайте это: stackoverflow.com/questions/601300/what-is-sql -injection и переключиться на параметризованные запросы. Старые функции mysql_ скоро станут устаревшими, вместо них следует использовать MySQLi.   -  person Polynomial    schedule 19.06.2012
comment
Танки в помощь. Однако это не решило мою проблему.   -  person Bird87 ZA    schedule 19.06.2012
comment
@DarkRanger: можете ли вы ввести echo $result перед циклом while и сообщить мне, что вы получите?   -  person Fahim Parkar    schedule 19.06.2012


Ответы (5)


Два периода времени P1 и P2 перекрываются тогда и только тогда, когда выполняется хотя бы одно из следующих условий:

  1. P1 начинается между началом и концом P2 (P2.from <= P1.from <= P2.to)
  2. P2 начинается между началом и концом P1 (P1.from <= P2.from <= P1.to)

Это позволит поймать частично перекрывающиеся периоды, а также периоды, когда один полностью перекрывает другой. Один из периодов всегда должен начинаться (или заканчиваться) внутри другого, если они перекрываются.

Таким образом, $another_meeting будет определяться:

$another_meeting = ($from >= $from_compare && $from <= $to_compare) ||
                   ($from_compare >= $from && $from_compare <= $to);

Вы можете изменить пограничные случаи на строгие < проверки того, может ли одно событие начаться в то же время, когда заканчивается другое.

person Emil Vikström    schedule 19.06.2012
comment
Кажется, это работает отлично. Я немного изменил его, чтобы обеспечить точно такое же время (я работаю с инженерами, и указание 14:01 вместо 14:00 кажется серьезной ошибкой). Baie Dankie (Большое спасибо на африкаанс) - person Bird87 ZA; 19.06.2012

Как раз делал что-то подобное.... но только со временем....

$startTime = strtotime("7:00");
$endTime   = strtotime("10:30");

$chkStartTime = strtotime("10:00");
$chkEndTime   = strtotime("12:10");

if($chkStartTime > $startTime && $chkEndTime < $endTime)
{
    // Check time is in between start and end time
    echo "1 Time is in between start and end time";
}
elseif(($chkStartTime > $startTime && $chkStartTime < $endTime) || ($chkEndTime > $startTime && $chkEndTime < $endTime))
{
    // Check start or end time is in between start and end time
    echo "2 ChK start or end Time is in between start and end time";
}
elseif($chkStartTime==$startTime || $chkEndTime==$endTime)
{
    // Check start or end time is at the border of start and end time
    echo "3 ChK start or end Time is at the border of start and end time";
}
elseif($startTime > $chkStartTime && $endTime < $chkEndTime)
{
    // start and end time is in between  the check start and end time.
    echo "4 start and end Time is overlapping  chk start and end time";
}
person Brian    schedule 19.06.2012

Я бы, наверное, решил это примерно так:

function avaliable($start, $end) {
  // checks if there's a meeting between start or end
  $q = "SELECT * FROM admin_boardroom_booking "
    . "WHERE NOT (meeting_start BETWEEN '$end' AND '$start' "
    . "OR meeting_end BETWEEN '$end' AND '$start')";
  $result = mysql_query($q);

  // returns true on no conflicts and false elseway
  return mysql_num_rows($result) === 0;
}
person nyson    schedule 19.06.2012
comment
Может сработать, но тогда мне также нужно будет проверить, не перекрывает ли встреча полностью другую. Пример: начинается встреча 1. Встреча 2 начинается, встреча 2 заканчивается, встреча 1 заканчивается. Глядя на ваш код, в этом случае он не вернет false... - person Bird87 ZA; 19.06.2012
comment
Ваши условия, к сожалению, неверны. Что произойдет, если значение $start будет предшествовать Meeting_start, а значение $end — после Meeting_end? Скобки будут оценены как false, а вы инвертируете их в true! Это также довольно странный подход к получению всех неконфликтующих встреч, когда вы действительно просто хотите знать, есть ли конфликты или нет. Вместо этого попробуйте сопоставить конфликтующие встречи и используйте COUNT(*) и LIMIT 1, чтобы немного ускорить это. - person Emil Vikström; 19.06.2012
comment
Кажется, я немного устал, я собираюсь переписать это ›___‹ - person nyson; 19.06.2012

Ответ Эмиля Викстрема правильный, но необходимо рассмотреть сценарий.
Например, один из временных диапазонов является подмножеством другого временного диапазона.
Итак, предположим, что P1{start_time, end_time} и P2{start_time, end_time} будут перекрываться, когда верно любое из следующих условий.

  • P1.start_time ‹= P2.start_time ‹= P1.end_time
  • P1.start_time ‹= P2.end_time ‹= P1.end_time
  • P2.start_time ‹= P1.start_time ‹= P1.end_time ‹= P2.end_time

Просто предполагая, что время отсортировано в порядке возрастания. Пример ниже:

|-----------------------------------|
|  Start time  |   End time  | Name |
|-----------------------------------|
|    10:00     |    14:00    |  P1  |
|-----------------------------------|
|    12:00     |    16:00    |  P2  |
|-----------------------------------|
|    08:00     |    12:00    |  P3  |
|-----------------------------------|
|    07:00     |    16:00    |  P4  |
|-----------------------------------|

Если вы считаете P1 базовым временем и хотите сверить с ним P2, P3, P4.

  1. P1.start_time ‹= P2.start_time ‹= P1.end_time true
  2. P1.start_time ‹= P3.end_time ‹= P1.end_time true
  3. P4.start_time ‹= P1.start_time ‹= P1.end_time ‹= P4.end_time true

Вот как вы можете проверить, перекрывается ли какое-либо время другим или нет.

person ssi-anik    schedule 29.10.2017
comment
Мой ответ уже решает это. Если P1 является полным подмножеством P2, то выполняется мое первое условие: P1 начнется внутри P2. - person Emil Vikström; 05.03.2018

В случае, когда $to всегда позже, чем $from, мы можем использовать более короткие решения.

$another_meeting = !($from > $to_compare || $from_compare > $to);
person Para-Diz    schedule 27.11.2018