how can disjunct 2 arrays of time ranges in php?
i have 2 arrays:
- availability (it's ranges when user available) and
- 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
Post a Comment