| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- <?php
- Class DateRanges {
- private $dateFormat = "Y-m-d";
- private $rangeSeparator = ";";
- private $dateSeparator = ":";
- private function strToArr($str) {
- return array_map(function ($range) {
- $_range = array_combine(['from', 'to'], array_map(function ($date) {
- if (!$date) return '';
- return DateTime::createFromFormat('!' . $this->dateFormat, $date)->getTimestamp();
- }, explode($this->dateSeparator, $range)));
- if ($_range['to'] && $_range['to'] < $_range['from']) throw new Exception("Date 'to' before date 'from'");
- return $_range;
- }, explode($this->rangeSeparator, $str));
- }
- private function arrToStr($arr) {
- return implode($this->rangeSeparator, array_map(function ($range) {
- return implode($this->dateSeparator, array_map(function ($date) {
- if (!$date) return '';
- return date($this->dateFormat, $date);
- }, $range));
- }, $arr));
- }
- private static function sort(&$ranges) {
- uasort($ranges, function($a, $b) {
- if ($a['from'] == $b['from']) {
- if ($a['to'] == $b['to']) return 0;
- if (!$a['to']) return 1;
- if (!$b['to']) return -1;
- return ($a['to'] < $b['to']) ? -1 : 1;
- }
- return ($a['from'] < $b['from']) ? -1 : 1;
- });
- }
- private function implodeRanges($ranges) {
- if (is_array($ranges)) {
- $ranges = implode($this->rangeSeparator, array_filter($ranges, function($range) {
- if ($range) return true;
- return false;
- }));
- }
- return $ranges;
- }
- private function _merge($ranges) {
- $ranges = $this->implodeRanges($ranges);
- if (!$ranges) throw new Exception("DataRanges::_merges - bad ranges");
- $ranges = $this->strToArr($ranges);
- self::sort($ranges);
- $result = [];
- foreach ($ranges as $range) {
- if (!$result) $result[] = $range;
- else {
- if (!end($result)['to']) break;
- $k = key($result);
- if ($range['from'] == $result[$k]['from']) $result[$k]['to'] = $range['to'];
- elseif ((!$range['to']) || ($range['to'] > $result[$k]['to'])) {
- if ($range['from'] > $result[$k]['to']) $result[] = $range;
- else $result[$k]['to'] = $range['to'];
- }
- }
- }
- return $this->arrToStr($result);
- }
- private static function lt($date1, $date2) {
- if (!$date1) return false;
- if (!$date2) return true;
- return ($date1 < $date2);
- }
- private static function gt($date1, $date2) {
- if (!$date2) return false;
- if (!$date1) return true;
- return ($date1 > $date2);
- }
- private static function le($date1, $date2) {
- return (!self::gt($date1, $date2));
- }
- private static function ge($date1, $date2) {
- return (!self::lt($date1, $date2));
- }
- private static function min($dates) {
- if ((!is_array($dates)) || (!$dates)) throw new Exception("DateRanges::min - bad arguments");
- $min = null;
- foreach ($dates as $date) {
- if ($min === null) {
- $min = $date;
- continue;
- }
- if (self::lt($date, $min)) $min = $date;
- }
- return $min;
- }
- private static function max($dates) {
- if ((!is_array($dates)) || (!$dates)) throw new Exception("DateRanges::max - bad arguments");
- $max = null;
- foreach ($dates as $date) {
- if ($max === null) {
- $max = $date;
- continue;
- }
- if (self::gt($date, $max)) $max = $date;
- }
- return $max;
- }
- private function _common($rangesA, $rangesB) {
- $rangesA = $this->implodeRanges($rangesA);
- $rangesB = $this->implodeRanges($rangesB);
- if (!($rangesA && $rangesB)) throw new Exception("DataRanges::_common - bad ranges");
- $rangesA = $this->strToArr($rangesA);
- $rangesB = $this->strToArr($rangesB);
- self::sort($rangesA);
- self::sort($rangesB);
- $ranges = [];
- foreach ($rangesA as $rangeA) {
- foreach ($rangesB as $rangeB) {
- // if ($rangeA['from'] == $rangeB['from'] && $rangeA['to'] == $rangeB['to']) {
- // $ranges[] = $rangeA;
- // continue;
- // }
- $range = [
- 'from' => self::max([$rangeA['from'], $rangeB['from']]),
- 'to' => self::min([$rangeA['to'], $rangeB['to']]),
- ];
- //print_r($range);
- if (self::le($range['from'], $range['to'])) { // || ($range['from'] == $range['to'] && ($rangeA['from'] == $rangeB['from'] || $rangeA['to'] == $rangeB['to']))) {
- $ranges[] = $range;
- }
- }
- }
- if (!$ranges) return null;
- return $this->_merge($this->arrToStr($ranges));
- }
- private function _days($ranges) {
- $ranges = $this->implodeRanges($ranges);
- if (!$ranges) throw new Exception("DataRanges::_days - bad ranges ({$ranges})");
- $ranges = $this->strToArr($ranges);
- $result = (int) 0;
- foreach ($ranges as $range) {
- if (!$range['from']) throw new Exception("DataRanges::_days - bad date from");
- if (!$range['to']) return -1;
- if ($range['to'] < $range['from']) throw new Exception("DataRanges::_days - date to before date from");
- $result += round(($range['to'] - $range['from']) / 86400);
- }
- return round($result);
- }
- public function __construct($dateFormat = null, $rangeSeparator = null, $dateSeparator = null) {
- if ($dateFormat !== null) $this->dateFormat = $dateFormat;
- if ($rangeSeparator !== null) $this->rangeSeparator = $rangeSeparator;
- if ($dateSeparator !== null) $this->dateSeparator = $dateSeparator;
- }
- public static function merge($ranges, $dateFormat = null, $rangeSeparator = null, $dateSeparator = null) {
- $obj = new DateRanges($dateFormat, $rangeSeparator, $dateSeparator);
- return $obj->_merge($ranges);
- }
- public static function common($rangesA, $rangesB, $dateFormat = null, $rangeSeparator = null, $dateSeparator = null) {
- $obj = new DateRanges($dateFormat, $rangeSeparator, $dateSeparator);
- return $obj->_common($rangesA, $rangesB);
- }
- public static function days($ranges, $dateFormat = null, $rangeSeparator = null, $dateSeparator = null) {
- $obj = new DateRanges($dateFormat, $rangeSeparator, $dateSeparator);
- return $obj->_days($ranges);
- }
- }
- class DateRanges_debug extends DateRanges {
- }
|