如何在php中分离两个日期时间范围数组

时间:2016-07-21 17:48:48

标签: php arrays

如何在PHP中分离两个时间范围数组?

我有两个数组:

  1. 可用性(用户可用时的范围)和
  2. 日期(当用户有约会时的范围)
  3. 状况

    [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
        )
    

    日期

    [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
        )
    

    我已将所有日期与可用性分开。如果你无法理解我所说的话,这就是退出这一分离时我应该拥有的:

    [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
        )
    

    它可能是偶数范围,而不仅仅是在一天之内 [dateTimeStart] => 2016-07-21 17:00:00 [dateTimeEnd] => 2016-07-22 01:30:00 。请帮助我或显示我必须去的地方。

1 个答案:

答案 0 :(得分:1)

splash58 commented所示,这是hakre's answer对此问题的演示:

$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
                        )

                )

        )

)

如果the source code被破坏,请参考the link以供参考。

/**
 * @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 and $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
            and $this->end == $range->end;
    }
    public function isWithin(Range $range) {
        return $range->start > $this->start
            and $range->end < $this->end;
    }
    public function isSubset(Range $range) {
        return $range->hasTime($this->start)
            and $range->hasTime($this->end);
    }
    public function add(Range $range) {
        if (!$this->hasContact($range)) {
            throw new InvalidArgumentException('Range needs to 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 would divide.');
        }
        if ($this->isSubset($range)) {
            throw new InvalidArgumentException('Range would 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 and end.');
                }
                $ranges = new Range($ranges, $end);
            }
            if ($ranges instanceof Range) {
                $ranges = [$ranges];
            }
            foreach ($ranges as $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 that is inside ranged time already');
            }
        }
        $this->ranges[] = $range;
    }
    /**
     * @param Range $range
     * @return Ranges
     */
    public function substractRange(Range $range) {
        $result = new self();
        foreach ($this as $member) {
            /* @var Range $member */
            foreach ($member->getDifferenceArray($range) as $new) {
                $result->append($new);
            }
        }
        $this->ranges = $result->ranges;
    }
    public function substract(Ranges $ranges) {
        $result = clone $this;
        foreach ($ranges as $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);
    }
}