简体   繁体   English

PHP:选择日期范围与日期范围重叠的日期

[英]PHP : Select overlapping date time ranges with time range overlapping day

I would like to know how to get date time ranges overlapping other date time ranges. 我想知道如何获取与其他日期时间范围重叠的日期时间范围。 The particularity is that a date range can have time range overlapping two consecutive days. 特殊之处在于,日期范围的时间范围可以连续两天重叠。

For example i have a recurrent reservation the 01/01 and 02/01 beginning at 20:00 and finishing the next day at 02:00. 例如,我有一个经常性的预订01/01和02/01,从20:00开始,第二天在02:00结束。

First day: 第一天:

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

Second day: 第二天:

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

Now i would like to know how to get reservations overlapping this reservation. 现在,我想知道如何获取与此预订重叠的预订。

Note: All reservations can have or not time range overlapping day. 注意:所有预订的日期都可以重叠或不重叠。

For example from a PHP point of view i have the following reservations : Dates and times are represented here as string for readability. 例如,从PHP的角度来看,我有以下保留:为了便于阅读,日期和时间在此表示为字符串。 In reality they are DateTime. 实际上,它们是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')
     ),
   ),
   ...
);

Thanks! 谢谢!

Use Objects to Make Life Easier 使用对象使生活更轻松

First, you really should simplify your structure. 首先,您确实应该简化结构。 If you really DO have dateTimes everywhere, then reservations should look something more like: 如果您确实确实到处都有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;
    }
}

Structuring your reservations this way will allow for some very simple solutions to your problem, like creating RecurringReservation which can generate an array of Reservations for a given date-range. 通过这种方式来构造您的预订,将为您的问题提供一些非常简单的解决方案,例如创建RecurringReservation ,它可以为给定的日期范围生成一系列的Reservations Or a Reservation->isToday() method which could check the $start and $stop properties in cases where it wraps midnight. 或者是Reservation->isToday()方法,它可以在午夜$start检查$start$stop属性。

For the problem you ask for however: 但是对于您所要求的问题:

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

Edit: I just realised you want an array of overlapping reservations: 编辑:我刚刚意识到你想要一个重叠的保留数组:

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

One last addendum, use Generators for creating lists of results. 最后一个附录,使用生成器创建结果列表。

Generators are awesome (when not misused). 生成器很棒(不被滥用时)。 They offer very high performance when you need a list of results. 当您需要结果列表时,它们可以提供非常高的性能。 They're only catch is that you have to pass their result straight into a loop to reap the benefits. 他们唯一能抓住的是,您必须将其结果直接传递到循环中才能获得好处。

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 
}

You want to test an appointment start is between the other appointment start and end, then same for the appointment end. 您要测试约会开始在另一个约会开始和结束之间,然后对约会结束进行相同的测试。 If either is true, you have an overlap. 如果任何一个为真,则您有一个重叠。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM