Intereting Posts
Создание XML-документа в PHP (escape-символы) Если нет вложения, тогда отправьте сообщение, иначе, кнопку загрузки изображения Как получить доступ к переменной memer a с символом Обнаруживать, существует ли сеанс PHP Как установить ImageMagick для WAMP 2.5 Как передать переменные с JavaScript на PHP? Как изменить корзину WooCommerce, страницы проверки (основная часть темы) Списки рассылки PHP (25K-100K) Что означает% S в PHP, HTML или XML? Какой обмен сообщениями об ошибках я могу вставить в этот скрипт, чтобы выяснить проблему Мой сервер был взломан закодированным кодом. я не мог узнать, в чем цель этого кода? Пожалуйста, помогите мне Можно ли загружать изображение на сервер с помощью диалогового окна «Модальное окно» Bootstrap, jQuery, AJAX и PHP? Если да, то как? Если нет, в чем причина? Установка клиента / драйвера PHP 7 MongoDB? Как обновить версию SQLite в комплекте с PHP Laravel: Где выбор для Eloquent Eager Загрузка отношений

Обнаружение конфликтов перекрытия событий календаря с использованием PHP

Я работаю над функцией, которая проверяет, сталкиваются ли внешние события с внутренними событиями (в приложении для календаря). Процесс выглядит следующим образом:

  • Мое приложение создает массив возможных событий (называемых $internalEvents )
  • Я источник внешних событий из календарей, таких как Календарь Google, iCloud и т. Д. (Называется $externalEvents ). Это существующие события с типом busy .
  • Теперь я должен проверить, есть ли какой-либо конфликт относительно внутренних и внешних событий. Я попробовал что-то, как вы можете видеть ниже, но это далеко не правильное или пуленепробиваемое.

Я старался как можно меньше сократить его. Это ввод данных:

 $internalEvents = array( array( "start" => "03/29/2016 12:00:00", "end" => "03/29/2016 13:00:00" ), array( "start" => "03/29/2016 12:30:00", "end" => "03/29/2016 13:30:00" ), array( "start" => "03/29/2016 13:00:00", "end" => "03/29/2016 14:00:00" ), array( "start" => "03/29/2016 13:30:00", "end" => "03/29/2016 14:50:00" ), array( "start" => "03/29/2016 14:00:00", "end" => "03/29/2016 15:00:00" ), array( "start" => "03/29/2016 14:30:00", "end" => "03/29/2016 15:30:00" ), array( "start" => "03/29/2016 15:00:00", "end" => "03/29/2016 16:00:00" ), array( "start" => "03/29/2016 15:30:00", "end" => "03/29/2016 16:30:00" ), array( "start" => "03/29/2016 16:00:00", "end" => "03/29/2016 17:00:00" ) ); $externalEvents = array( array( "start" => "03/29/2016 08:00:00", "end" => "03/29/2016 12:00:00", "type" => "busy" ), array( "start" => "03/29/2016 15:30:00", "end" => "03/29/2016 16:00:00", "type" => "busy" ), array( "start" => "03/29/2016 13:30:00", "end" => "03/29/2016 14:15:00", "type" => "busy" ) ); 

Теперь я пытаюсь найти любой конфликт, сравнивая внутреннее событие со всеми внешними событиями:

 foreach($internalEvents as $internalEvent) { $internalEventStart = new DateTime($internalEvent['start']); $internalEventEnd = new DateTime($internalEvent['end']); $result = true; echo "\nverifying " . $internalEventStart->format('Ymd H:i') . " - " . $internalEventEnd->format('Ymd H:i') . "\n"; foreach($externalEvents as $externalEvent) { $externalEventStart = new DateTime($externalEvent['start']); $externalEventEnd = new DateTime($externalEvent['end']); // check if there are conflicts between internal and external events if ($internalEventStart >= $externalEventStart && $internalEventStart <= $externalEventEnd) { $result = false; echo " problem 1: event is between busy time: " . "\n"; } if ($internalEventStart >= $externalEventStart && $internalEventStart <= $externalEventEnd && $externalEventEnd <= $internalEventEnd) { $result = false; echo " problem 2: event starts during busy time: " . "\n"; } if ($internalEventStart <= $externalEventStart && $externalEventStart <= $internalEventEnd && $internalEventEnd <= $externalEventEnd) { $result = false; echo " problem 3: event stops during busy time: " . "\n"; } if (($internalEventStart <= $externalEventStart) && ($externalEventStart <= $externalEventEnd) && ($externalEventEnd <= $internalEventEnd)) { $result = false; echo " problem 4: event during busy time: " . "\n"; } if (($internalEventStart <= $internalEventEnd) && ($internalEventEnd <= $externalEventStart) && ($externalEventStart <= $externalEventEnd)) { $result = false; echo " problem 5: event during busy time: " . "\n"; } } if($result) { echo " result: OK\n"; } else { echo " result: NOT OK \n"; } } 

Я ищу алгоритм, который может найти любой возможный конфликт перекрытия событий. Любой намек высоко ценится.

Прогон кода можно найти здесь (IDEone.com).

Когда сталкиваются два события? См. Эту схему:

  ----E---- CS/EE CE/ES --N-- < < --N-- > > --C-- < > --C-- < > --C-- < > -----C----- < > ·················································· E = Main Event N = Not Collide Event C = Collide Event CS = Compare Event Start EE = Main Event End CE = Compare Event End ES = Main Event Start 

Как вы можете видеть, столкновение происходит только тогда, когда начало события C до конца события E, а конец события E – после начала события C. Знание этого помогает найти эффективный и короткий метод для сравнения событий.

О коде, предварительное примечание: вы конвертируете даты в ISO 8601, прежде чем сравнивать их несколько раз в своем коде, так почему бы не создать функцию для этого?

 function eventsToDate( $row ) { $retval = array( 'start' => date_create( $row['start'] )->format('Ymd H:i:s'), 'end' => date_create( $row['end'] )->format('Ymd H:i:s') ); $retval['print'] = sprintf( '%s-%s', substr( $retval['start'],-8,5 ), substr( $retval['end'],-8,5 ) ); return $retval; } 

Эта функция возвращает ассоциативный массив с 'start' и 'end' в вашем формате. Я добавил третий ключ, 'print', чтобы использовать его во время отладки. Обратите внимание, что в печати я рассматриваю только часы: минуты (все даты в вашем примере массива с одного дня), но сравнение производится в полные даты. Вы можете опустить этот «печатный» ключ или заменить его предпочтительным форматом вывода.

Вы выполняете два вложенных foreach , и для каждого цикла пересчитываете формат даты. С образцами массива вы вызываете DateTime / DateTime :: format 36 раз. Создав временный массив со всеми преобразованными $externalEvents , мы можем уменьшить эти вызовы до 12. Итак, перед запуском цикла foreach() мы используем array_map с array_map функцией и массивом $externalEvents для создания массива с отформатированными датами:

 $externalDates = array_map( 'eventsToDate', $externalEvents ); 

Затем мы начинаем основной цикл foreach() на $internalEvents :

 foreach( $internalEvents as $internalEvent ) { $internalDates = eventsToDate( $internalEvent ); echo $internalDates['print'] . PHP_EOL; $result = True; foreach( $externalDates as $externalDate ) { 

На данный момент мы сравниваем даты. Как упоминалось выше, мы начинаем с начала и конца с начала. Чтобы упростить следующее сравнение, мы используем strcmp , php, которая «возвращает <0, если str1 меньше str2,> 0, если str1 больше str2, а 0, если они равны»:

  $startCmp = strcmp( $internalDates['start'], $externalDate['end'] ); $endCmp = strcmp( $internalDates['end'], $externalDate['start'] ); 

Теперь, сравнение:

  if( $startCmp<0 && $endCmp>0 ) { $result = False; echo " {$externalDate['print']} COLLIDE\n"; } else { echo " {$externalDate['print']} OK\n"; } } 

И, наконец, мы можем напечатать результат:

  echo "Result: " . ( $result ? 'OK' : 'NOT OK') . "\n\n"; } 

Демо-версия eval.in

Примечание: при сравнении выше, с первым $internalEvent получаем следующий результат:

 12:00-13:00 08:00-12:00 OK 15:30-16:00 OK 13:30-14:15 OK Result: OK 

Вместо этого, если вы хотите получить этот результат:

 12:00-13:00 08:00-12:00 COLLIDE 15:30-16:00 OK 13:30-14:15 OK Result: NOT OK 

Вы должны заменить выше, if условие:

  if( $startCmp<=0 && $endCmp>=0 ) 

Над кодом будет работать, если вы хотите получить более подробную информацию о виде столкновения, вы можете проверить другие комбинации начала и конца внутри условия if .


Альтернатива: Возвращающиеся сталкивающиеся события

Если вместо печати результатов вы хотите поймать встречные события, вы можете заменить вложенный foreach() на array_filter таким образом:

 $result = array_filter ( $externalDates, function( $row ) use( $internalDates ) { $startCmp = strcmp( $internalDates['start'], $row['end'] ); $endCmp = strcmp( $internalDates['end'], $row['start'] ); return( $startCmp<0 && $endCmp>0 ); } ); 

На этом этапе встречные события находятся в массиве $result . Очевидно, что массив пуст, конфликтов нет.


  • Узнайте больше о strcmp ()
  • Подробнее о array_map ()
  • Подробнее о array_filter ()