Procházet zdrojové kódy

Klasa do opracji na zakresach dat

Mariusz Muszyński před 7 roky
rodič
revize
1882dc7eed
1 změnil soubory, kde provedl 185 přidání a 0 odebrání
  1. 185 0
      SE/se-lib/DateRanges.php

+ 185 - 0
SE/se-lib/DateRanges.php

@@ -0,0 +1,185 @@
+<?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 {
+}