PHP: выбор перекрывающихся диапазонов даты и времени с перекрывающимся днем

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

Например, у меня есть периодическое бронирование 01/01 и 02/01, начинающееся в 20:00 и заканчивающееся на следующий день в 02:00.

Первый день:

$start = '2017-01-01 20:00';
$end =   '2017-01-02 02:00';

Второй день:

$start = '2017-01-02 20:00';
$end =   '2017-01-03 02:00';

Теперь я хотел бы знать, как получить бронирование, перекрывающее это бронирование.

Примечание: все бронирования могут иметь или не перекрывать день.

Например, с точки зрения PHP у меня есть следующие оговорки:
Даты и время представлены здесь в виде строки для удобства чтения. На самом деле это DateTime.

//The reservation
$reservation= array(
array(
'day' => '2017-01-01',
'time_range' => array('20:00', '23:59')
),
array(
'day' => '2017-01-02',
'time_range' => array('00:00', '02:00')
),
);

//Other reservations
$reservations= array(
//Reservation doesn't overlap
array(
'day' => '2017-01-01',
'time_range' => array('18:00', '19:00')
),
//Reservation overlaps
array(
'day' => '2017-01-01',
'time_range' => array('21:00', '22:00')
),
//Reservation overlaps
array(
array(
'day' => '2017-01-01',
'time_range' => array('23:00', '23:59')
),
array(
'day' => '2017-01-02',
'time_range' => array('00:00', '01:00')
),
),
...
);

Спасибо!

0

Решение

Во-первых, вы действительно должны упростить свою структуру. Если у вас действительно есть dateTimes везде, то резервирование должно выглядеть примерно так:

class Reservation
{
/** @var DateTime $start */
public $start;
/** @var DateTime $stop */
public $stop;

public function _construct(DateTime $start, DateTime $stop): void
{
$this->start = $start;
$this->stop = $stop;
}

public function isOverlapping(Reservation $reservation): bool
{
if ($reservation->start >= $this->start && $reservation->start <= $this->stop) {
// starts during reservation
return true;
}

if ($reservation->stop >= $this->start && $reservation->stop <= $this->stop) {
// ends during reservation
return true;
}

if ($reservation->start <= $this->start && $reservation->end >= $this->stop) {
// $this is contained by $reservation
return true;
}

return false;
}
}

Структурирование ваших бронирований таким способом позволит вам найти несколько очень простых решений вашей проблемы, таких как создание RecurringReservation который может генерировать массив Reservations для данного диапазона дат. Или Reservation->isToday() метод, который может проверить $start а также $stop свойства в тех случаях, когда он охватывает полночь.

class Reservation
{

. . .

public function anyOverlap(array $reservations): bool
{
foreach ($reservations as $checkMe) {
if ($this->isOverlapping($checkMe)) {
return true;
}
}
return false;
}
}

$reservation = new Reservation(new DateTime('2017-01-01 20:00'), new DateTime('2017-01-02 02:00'));

$reservations = [
new Reservation(new DateTime('2017-01-01 18:00'), new DateTime('2017-01-01 19:00')),
new Reservation(new DateTime('2017-01-01 21:00'), new DateTime('2017-01-01 22:00')),
new Reservation(new DateTime('2017-01-01 23:00'), new DateTime('2017-01-02 01:00')),
];

$reservation->anyOverlap($reservations); // true
class Reservation
{

. . .

public function getOverlapping(array $reservations): array
{
$result = [];
foreach ($reservations as $checkMe) {
if ($this->isOverlapping($checkMe)) {
$result[] = $checkMe;
}
}
return $result;
}
}

. . .

$overlapping = $reservation->getOverlapping($reservations); // array

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

public function getOverlapping(array $reservations): Generator
{
foreach ($reservations as $checkMe) {
if ($this->isOverlapping($checkMe)) {
yield $checkMe;
}
}
}

...

foreach($reservation->getOverlapping($reservations) as $overlap) {
yellAtReceptionistFor($overlap); // ... or whatever
}
1

Другие решения

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

-1

По вопросам рекламы [email protected]