Разделить временной диапазон на части по другим временным диапазонам

У меня сложная задача: я уже несколько дней бил головой о стену. Я пробовал около 4 разных подходов, однако каждый из них, похоже, останавливается, и это становится очень неприятным.

У меня есть временной диапазон. Например, с 14:30 до 18:30. Рассматривайте этот временной диапазон чей-то рабочий сдвиг. В течение этого периода времени они заявляют, что они не могут работать с 15:30 до 16:30 и с 17:30 до 18:30. Мне нужно изменить начальные и конечные времена исходного сдвига, чтобы удалить конфликтующие сдвиги.

Оригинальная матрица сдвига выглядит так:

$original_shift[0]['start'] = '14:30:00'; $original_shift[0]['end'] = '18:30:00'; 

И диапазоны времени, которые нужно удалить из первоначальной смены, выглядят следующим образом:

 $subshift[0]['start'] = '15:30:00'; $subshift[0]['end'] = '16:30:00'; $subshift[1]['start'] = '17:30:00'; $subshift[1]['end'] = '18:30:00'; 

Вот визуализация:

введите описание изображения здесь

Итак, мне в основном нужен мой первоначальный переход, чтобы выглядеть так, когда я закончил:

 $original_shift[0]['start'] = '14:30:00'; $original_shift[0]['end'] = '15:30:00'; $original_shift[1]['start'] = '16:30:00'; $original_shift[1]['end'] = '17:30:00'; 

Некоторые осложнения, которые мне также необходимо учитывать, следующие:

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

  2. Недоступные времена могут зависнуть и / или полностью вернуть время оригинального переключения.

Я не ищу, чтобы кто-то «писал мой код» настолько, насколько я ищу кого-то, кто имел дело с чем-то подобным в прошлом, и может иметь некоторое представление о том, как они это сделали.

Solutions Collecting From Web of "Разделить временной диапазон на части по другим временным диапазонам"

Поскольку вы специально просили «немного понять», а не полный рабочий ответ, я бы лично пошел с массивами, заполненными «минутами».

 $shift = array( 'start' => '15:30:00', 'end' => '18:30:00', 'original' => array(), 'unavailable' => array(), 'modified' => array() ); 

Затем вы сделаете некоторое подросток для конвертации 15:30:00 в 930 и 18:30:00 в 1110 (количество минут), что даст вам разницу между временем начала и окончания.

Используйте range() чтобы быстро заполнить original массив, загрузить его в unavailable в аналогичном формате, а затем использовать такие вещи, как array_intersect() и array_diff() чтобы определить, какие минуты из первоначальной смены недоступны.

Исходя из этого, создайте modified массив и прочитайте прямо оттуда к вашему выводу.

Вам нужно делать расчеты временных диапазонов. Как видно на рисунке, это похоже на простое вычитание. Было бы неплохо иметь объекты, которые это делают.

У меня не было кода для этого, поэтому следующая концепция немного грубо, хотя, вероятно, не так уж плохо.

Тип Range который представляет время от-до. Это как DateTime так что можно использовать преимущества этих существующих типов. Я пока не использовал большую часть преимуществ, однако для остальной части приложения это может иметь смысл.

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

Однако, поскольку объект не может делить себя на два, я также создал тип Ranges который может представлять один или несколько Range s. Это было необходимо, чтобы иметь что-то, что можно «разделить».

Я немного обманул, потому что я выполнил разностный расчет как член Range , возвратив массив с одним или несколькими объектами Range . Окончательный расчет затем имеет только сдвиг и вычитает недоступные диапазоны:

 $shift = new Ranges(new DateTime('14:30:00'), new DateTime('18:30:00')); $unavailables = new Ranges([ new Range(new DateTime('15:30:00'), new DateTime('16:30:00')), new Range(new DateTime('17:30:00'), new DateTime('18:30:00')), ]); $shift->subtract($unavailables); 

Затем сдвиг охватывает:

 14:30:00 - 15:30:00 16:30:00 - 17:30:00 

Демо ; Суть

Я не могу сказать, стоит ли абстракции, что хорошо с объектами DateTime это то, что вы можете сравнить их с > , < и = . Реальная польза от этих классов может пролить свет, когда вам нужно больше вычислений между диапазонами и диапазонами. Может быть, интерфейс еще не милый, однако основные расчеты позади уже описаны в коде.

Одно предостережение: различие между 14:00-15:00 и 14:00-15:00 в моем коде приведет к 14:00-14:00 . Я держу время начала, чтобы не запускать пустым, но вы также можете запустить пустым. Объект Ranges должен хорошо его обрабатывать.

Код должен говорить сам за себя:

 $original_shift[0]['start'] = '14:30:00'; $original_shift[0]['end'] = '18:30:00'; $breaks[0]['start'] = '14:30:00'; $breaks[0]['end'] = '15:30:00'; $breaks[1]['start'] = '16:30:00'; $breaks[1]['end'] = '17:30:00'; $modified_shift = array( array('start' => $original_shift[0]['start']) ); for($x = 0, $y = count($breaks), $z = 0; $x < $y; $x++){ $modified_shift[$z]['end'] = $breaks[$x]['start']; if($modified_shift[$z]['end'] != $modified_shift[$z]['start']){ $z++; } $modified_shift[$z]['start'] = $breaks[$x]['end']; } $modified_shift[$z]['end'] = $original_shift[0]['end']; if($modified_shift[$z]['end'] == $modified_shift[$z]['start']){ unset($modified_shift[$z]); } с $original_shift[0]['start'] = '14:30:00'; $original_shift[0]['end'] = '18:30:00'; $breaks[0]['start'] = '14:30:00'; $breaks[0]['end'] = '15:30:00'; $breaks[1]['start'] = '16:30:00'; $breaks[1]['end'] = '17:30:00'; $modified_shift = array( array('start' => $original_shift[0]['start']) ); for($x = 0, $y = count($breaks), $z = 0; $x < $y; $x++){ $modified_shift[$z]['end'] = $breaks[$x]['start']; if($modified_shift[$z]['end'] != $modified_shift[$z]['start']){ $z++; } $modified_shift[$z]['start'] = $breaks[$x]['end']; } $modified_shift[$z]['end'] = $original_shift[0]['end']; if($modified_shift[$z]['end'] == $modified_shift[$z]['start']){ unset($modified_shift[$z]); }