How to disjunct two arrays of datetime ranges in php -


how can disjunct 2 arrays of time ranges in php?

i have 2 arrays:

  1. availability (it's ranges when user available) and
  2. dates (it's ranges when user have date)

availability

[0] => array     (         [datetimestart] => 2016-07-21 00:00:00         [datetimeend] => 2016-07-21 15:00:00     )  [3] => array     (         [datetimestart] => 2016-07-21 17:00:00         [datetimeend] => 2016-07-21 19:30:00     ) 

dates

[0] => array     (         [datetimestart] => 2016-07-21 08:00:00         [datetimeend] => 2016-07-21 12:00:00     )  [1] => array     (         [datetimestart] => 2016-07-21 18:30:00         [datetimeend] => 2016-07-21 19:30:00     ) 

and have disjunct dates availability. if can't understand i'm talking about, should have on exit of disjunction:

[0] => array     (         [datetimestart] => 2016-07-21 00:00:00         [datetimeend] => 2016-07-21 8:00:00     ) [1] => array     (         [datetimestart] => 2016-07-21 12:00:00         [datetimeend] => 2016-07-21 15:00:00     )  [2] => array     (         [datetimestart] => 2016-07-21 17:00:00         [datetimeend] => 2016-07-21 18:30:00     ) 

it ranges not in 1 day [datetimestart] => 2016-07-21 17:00:00 [datetimeend] => 2016-07-22 01:30:00 . please, me or show have go.

as splash58 commented, here's demonstration of hakre's answer question:

$shift = new ranges([     new range(new datetime('2016-07-21 00:00:00'), new datetime('2016-07-21 15:00:00')),     new range(new datetime('2016-07-21 17:00:00'), new datetime('2016-07-21 19:30:00')), ]);  $unavailables = new ranges([     new range(new datetime('2016-07-21 08:00:00'), new datetime('2016-07-21 12:00:00')),     new range(new datetime('2016-07-21 18:30:00'), new datetime('2016-07-21 19:30:00')), ]);  print_r($shift); 
ranges object (     [ranges:protected] => array         (             [0] => range object                 (                     [start:protected] => datetime object                         (                             [date] => 2016-07-21 00:00:00                             [timezone_type] => 3                             [timezone] => america/chicago                         )                      [end:protected] => datetime object                         (                             [date] => 2016-07-21 08:00:00                             [timezone_type] => 3                             [timezone] => america/chicago                         )                  )              [1] => range object                 (                     [start:protected] => datetime object                         (                             [date] => 2016-07-21 12:00:00                             [timezone_type] => 3                             [timezone] => america/chicago                         )                      [end:protected] => datetime object                         (                             [date] => 2016-07-21 15:00:00                             [timezone_type] => 3                             [timezone] => america/chicago                         )                  )              [2] => range object                 (                     [start:protected] => datetime object                         (                             [date] => 2016-07-21 17:00:00                             [timezone_type] => 3                             [timezone] => america/chicago                         )                      [end:protected] => datetime object                         (                             [date] => 2016-07-21 18:30:00                             [timezone_type] => 3                             [timezone] => america/chicago                         )                  )          )  ) 

here's the source code reference in case the link broken.

/**  * @link https://stackoverflow.com/questions/13129336/split-a-time-range-into-pieces-by-other-time-ranges  * @link https://gist.github.com/gists/3977645  * @author hakre  */ class range {     /**      * @var datetime      */     protected $start;     /**      * @var datetime      */     protected $end;     public function __construct(datetime $start, datetime $end) {         $this->setstart($start);         $this->setend($end);     }     /**      * @return datetime      */     public function getstart() {         return $this->start;     }     public function setstart(datetime $start) {         $this->start = $start;     }     /**      * @return \datetime      */     public function getend() {         return $this->end;     }     /**      * @param datetime $end      * @throws invalidargumentexception      */     public function setend(datetime $end) {         if ($end < $this->start) {             throw new invalidargumentexception('end before start');         }         $this->end = $end;     }     public function hastime(datetime $time) {         return $this->start <= $time , $this->end >= $time;     }     public function hascontact(range $range) {         return $this->hastime($range->start)             or $this->hastime($range->end);     }     public function issame(range $range) {         return $this->start == $range->start             , $this->end == $range->end;     }     public function iswithin(range $range) {         return $range->start > $this->start             , $range->end < $this->end;     }     public function issubset(range $range) {         return $range->hastime($this->start)             , $range->hastime($this->end);     }     public function add(range $range) {         if (!$this->hascontact($range)) {             throw new invalidargumentexception('range needs overlap.');         }         if ($range->start < $this->start) {             $this->start = $range->start;         }         if ($range->end > $this->end) {             $this->end = $range->end;         }     }     public function substract(range $range) {         if ($this->iswithin($range)) {             throw new invalidargumentexception('range divide.');         }         if ($this->issubset($range)) {             throw new invalidargumentexception('range delete.');         }         if (!$this->hascontact($range)) {             return;         }         if ($range->start == $this->start) {             $this->start = $range->end;             return;         }         if ($range->end == $this->end) {             $this->end = $range->start;             return;         }         if ($range->start < $this->end) {             $this->end = $range->start;         } elseif ($range->end > $this->start) {             $this->start = $range->end;         }     }     public function getdifferencearray(range $range) {         if ($this->issubset($range)) {             return [];         }         if (!$this->hascontact($range)) {             return [clone $this];         }         if ($this->iswithin($range)) {             $result[1] = clone $result[0] = clone $this;             $result[0]->end   = $range->start;             $result[1]->start = $range->end;             return $result;         }         $result = clone $this;         $result->substract($range);         return [$result];     }     public function format($format) {         return [             $this->start->format($format),             $this->end->format($format)         ];     } } class ranges implements iteratoraggregate, countable {     protected $ranges = [];     public function __construct($ranges = null, datetime $end = null) {         if ($ranges) {             if ($ranges instanceof datetime) {                 if (null === $end) {                     throw new invalidargumentexception('need start , end.');                 }                 $ranges = new range($ranges, $end);             }             if ($ranges instanceof range) {                 $ranges = [$ranges];             }             foreach ($ranges $range) {                 $this->append($range);             }         }     }     public function getstart() {         if (!$this->ranges) {             throw new badmethodcallexception('enpty range');         }         return $this->ranges[0]->getstart();     }     public function getend() {         if (!$this->ranges) {             throw new badmethodcallexception('enpty range');         }         return $this->ranges[count($this->ranges) - 1]->getend();     }     public function append(range $range) {         if ($this->ranges) {             if ($range->getstart() <= $this->getend()) {                 throw new invalidargumentexception('can not append range inside ranged time already');             }         }         $this->ranges[] = $range;     }     /**      * @param range $range      * @return ranges      */     public function substractrange(range $range) {         $result = new self();         foreach ($this $member) {             /* @var range $member */             foreach ($member->getdifferencearray($range) $new) {                 $result->append($new);             }         }         $this->ranges = $result->ranges;     }     public function substract(ranges $ranges) {         $result = clone $this;         foreach ($ranges $range) {             $result->substractrange($range);         }         $this->ranges = $result->ranges;     }     public function getiterator() {         return new arrayiterator($this->ranges);     }     public function getrange() {         return new range($this->getstart(), $this->getend());     }     public function count() {         return count($this->ranges);     } } 

Comments