summaryrefslogtreecommitdiffstats
path: root/vendor/simshaun/recurr/src/Recurr/DateUtil.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/simshaun/recurr/src/Recurr/DateUtil.php')
-rw-r--r--vendor/simshaun/recurr/src/Recurr/DateUtil.php571
1 files changed, 571 insertions, 0 deletions
diff --git a/vendor/simshaun/recurr/src/Recurr/DateUtil.php b/vendor/simshaun/recurr/src/Recurr/DateUtil.php
new file mode 100644
index 0000000..48a4e87
--- /dev/null
+++ b/vendor/simshaun/recurr/src/Recurr/DateUtil.php
@@ -0,0 +1,571 @@
+<?php
+
+/*
+ * Copyright 2013 Shaun Simmons
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * Based on rrule.js
+ * Copyright 2010, Jakub Roztocil and Lars Schoning
+ * https://github.com/jkbr/rrule/blob/master/LICENCE
+ *
+ * Based on python-dateutil - Extensions to the standard Python datetime module.
+ * Copyright (c) 2003-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
+ * Copyright (c) 2012 - Tomi Pieviläinen <tomi.pievilainen@iki.fi>
+ */
+
+namespace Recurr;
+
+/**
+ * Class DateUtil is responsible for providing utilities applicable to Rules.
+ *
+ * @package Recurr
+ * @author Shaun Simmons <shaun@envysphere.com>
+ */
+class DateUtil
+{
+ public static $leapBug = null;
+
+ public static $monthEndDoY366 = array(
+ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
+ );
+
+ public static $monthEndDoY365 = array(
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+ );
+
+ public static $wDayMask = array(
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
+ 0, 1, 2, 3, 4, 5, 6,
+ );
+
+ /**
+ * Get an object containing info for a particular date
+ *
+ * @param \DateTimeInterface $dt
+ *
+ * @return DateInfo
+ */
+ public static function getDateInfo(\DateTimeInterface $dt)
+ {
+ $i = new DateInfo();
+ $i->dt = $dt;
+ $i->dayOfWeek = self::getDayOfWeek($dt);
+ $i->monthLength = $dt->format('t');
+ $i->yearLength = self::getYearLength($dt);
+
+ $i->mMask = self::getMonthMask($dt);
+ $i->mDayMask = self::getMonthDaysMask($dt);
+ $i->mDayMaskNeg = self::getMonthDaysMask($dt, true);
+
+ if ($i->yearLength == 365) {
+ $i->mRanges = self::$monthEndDoY365;
+ } else {
+ $i->mRanges = self::$monthEndDoY366;
+ }
+
+ $tmpDt = clone $dt;
+ $tmpDt = $tmpDt->setDate($dt->format('Y') + 1, 1, 1);
+ $i->nextYearLength = self::getYearLength($tmpDt);
+
+ $tmpDt = clone $dt;
+ $tmpDt = $tmpDt->setDate($dt->format('Y'), 1, 1);
+ $i->dayOfWeekYearDay1 = self::getDayOfWeek($tmpDt);
+
+ $i->wDayMask = array_slice(
+ self::$wDayMask,
+ $i->dayOfWeekYearDay1
+ );
+
+ return $i;
+ }
+
+ /**
+ * Get an array of DOY (Day of Year) for each day in a particular week.
+ *
+ * @param \DateTimeInterface $dt
+ * @param \DateTimeInterface $start
+ * @param null|Rule $rule
+ * @param null|DateInfo $dtInfo
+ *
+ * @return DaySet
+ */
+ public static function getDaySetOfWeek(
+ \DateTimeInterface $dt,
+ \DateTimeInterface $start,
+ Rule $rule = null,
+ DateInfo $dtInfo = null
+ )
+ {
+ $start = clone $dt;
+ $start = $start->setDate($start->format('Y'), 1, 1);
+
+ $diff = $dt->diff($start);
+ $start = $diff->days;
+
+ $set = array();
+ for ($i = $start, $k = 0; $k < 7; $k++) {
+ $set[] = $i;
+ ++$i;
+
+ if (null !== $dtInfo && null !== $rule && $dtInfo->wDayMask[$i] == $rule->getWeekStartAsNum()) {
+ break;
+ }
+ }
+
+ $obj = new DaySet($set, $start, $i);
+
+ return $obj;
+ }
+
+ /**
+ * @param Rule $rule
+ * @param \DateTimeInterface $dt
+ * @param DateInfo $dtInfo
+ * @param \DateTimeInterface $start
+ *
+ * @return DaySet
+ */
+ public static function getDaySet(Rule $rule, \DateTimeInterface $dt, DateInfo $dtInfo, $start)
+ {
+ switch ($rule->getFreq()) {
+ case Frequency::SECONDLY:
+ return self::getDaySetOfDay($dt, $start, $rule, $dtInfo);
+ break;
+ case Frequency::MINUTELY:
+ return self::getDaySetOfDay($dt, $start, $rule, $dtInfo);
+ break;
+ case Frequency::HOURLY:
+ return self::getDaySetOfDay($dt, $start, $rule, $dtInfo);
+ break;
+ case Frequency::DAILY:
+ return self::getDaySetOfDay($dt, $start, $rule, $dtInfo);
+ break;
+ case Frequency::WEEKLY:
+ return self::getDaySetOfWeek($dt, $start, $rule, $dtInfo);
+ case Frequency::MONTHLY:
+ return self::getDaySetOfMonth($dt, $start, $rule, $dtInfo);
+ case Frequency::YEARLY:
+ return self::getDaySetOfYear($dt, $start, $rule, $dtInfo);
+ }
+
+ throw new \RuntimeException('Invalid freq.');
+ }
+
+ /**
+ * Get an array of DOY (Day of Year) for each day in a particular year.
+ *
+ * @param \DateTimeInterface $dt The datetime
+ *
+ * @return DaySet
+ */
+ public static function getDaySetOfYear(\DateTimeInterface $dt)
+ {
+ $yearLen = self::getYearLength($dt);
+ $set = range(0, $yearLen - 1);
+
+ return new DaySet($set, 0, $yearLen);
+ }
+
+ /**
+ * Get an array of DOY (Day of Year) for each day in a particular month.
+ *
+ * @param \DateTimeInterface $dt The datetime
+ *
+ * @return DaySet
+ */
+ public static function getDaySetOfMonth(\DateTimeInterface $dt)
+ {
+ $dateInfo = self::getDateInfo($dt);
+ $monthNum = $dt->format('n');
+
+ $start = $dateInfo->mRanges[$monthNum - 1];
+ $end = $dateInfo->mRanges[$monthNum];
+
+ $days = range(0, $dt->format('t') - 1);
+ $set = range($start, $end - 1);
+ $set = array_combine($days, $set);
+ $obj = new DaySet($set, $start, $end - 1);
+
+ return $obj;
+ }
+
+ /**
+ * Get an array of DOY (Day of Year) for each day in a particular month.
+ *
+ * @param \DateTimeInterface $dt The datetime
+ *
+ * @return DaySet
+ */
+ public static function getDaySetOfDay(\DateTimeInterface $dt)
+ {
+ $dayOfYear = $dt->format('z');
+
+ if (self::isLeapYearDate($dt) && self::hasLeapYearBug() && $dt->format('nj') > 229) {
+ $dayOfYear -= 1;
+ }
+
+ $start = $dayOfYear;
+ $end = $dayOfYear;
+
+ $set = range($start, $end);
+ $obj = new DaySet($set, $start, $end + 1);
+
+ return $obj;
+ }
+
+ /**
+ * @param Rule $rule
+ * @param \DateTimeInterface $dt
+ *
+ * @return array
+ */
+ public static function getTimeSetOfHour(Rule $rule, \DateTimeInterface $dt)
+ {
+ $set = array();
+
+ $hour = $dt->format('G');
+ $byMinute = $rule->getByMinute();
+ $bySecond = $rule->getBySecond();
+
+ if (empty($byMinute)) {
+ $byMinute = array($dt->format('i'));
+ }
+
+ if (empty($bySecond)) {
+ $bySecond = array($dt->format('s'));
+ }
+
+ foreach ($byMinute as $minute) {
+ foreach ($bySecond as $second) {
+ $set[] = new Time($hour, $minute, $second);
+ }
+ }
+
+ return $set;
+ }
+
+ /**
+ * @param Rule $rule
+ * @param \DateTimeInterface $dt
+ *
+ * @return array
+ */
+ public static function getTimeSetOfMinute(Rule $rule, \DateTimeInterface $dt)
+ {
+ $set = array();
+
+ $hour = $dt->format('G');
+ $minute = $dt->format('i');
+ $bySecond = $rule->getBySecond();
+
+ if (empty($bySecond)) {
+ $bySecond = array($dt->format('s'));
+ }
+
+ foreach ($bySecond as $second) {
+ $set[] = new Time($hour, $minute, $second);
+ }
+
+ return $set;
+ }
+
+ /**
+ * @param \DateTimeInterface $dt
+ *
+ * @return array
+ */
+ public static function getTimeSetOfSecond(\DateTimeInterface $dt)
+ {
+ return array(new Time($dt->format('G'), $dt->format('i'), $dt->format('s')));
+ }
+
+ /**
+ * @param Rule $rule
+ * @param \DateTimeInterface $dt
+ *
+ * @return array
+ */
+ public static function getTimeSet(Rule $rule, \DateTimeInterface $dt)
+ {
+ $set = array();
+
+ if (null === $rule || $rule->getFreq() >= Frequency::HOURLY) {
+ return $set;
+ }
+
+ $byHour = $rule->getByHour();
+ $byMinute = $rule->getByMinute();
+ $bySecond = $rule->getBySecond();
+
+ if (empty($byHour)) {
+ $byHour = array($dt->format('G'));
+ }
+
+ if (empty($byMinute)) {
+ $byMinute = array($dt->format('i'));
+ }
+
+ if (empty($bySecond)) {
+ $bySecond = array($dt->format('s'));
+ }
+
+ foreach ($byHour as $hour) {
+ foreach ($byMinute as $minute) {
+ foreach ($bySecond as $second) {
+ $set[] = new Time($hour, $minute, $second);
+ }
+ }
+ }
+
+ return $set;
+ }
+
+ /**
+ * Get a reference array with the day number for each day of each month.
+ *
+ * @param \DateTimeInterface $dt The datetime
+ * @param bool $negative
+ *
+ * @return array
+ */
+ public static function getMonthDaysMask(\DateTimeInterface $dt, $negative = false)
+ {
+ if ($negative) {
+ $m29 = range(-29, -1);
+ $m30 = range(-30, -1);
+ $m31 = range(-31, -1);
+ } else {
+ $m29 = range(1, 29);
+ $m30 = range(1, 30);
+ $m31 = range(1, 31);
+ }
+
+ $mask = array_merge(
+ $m31, // Jan (31)
+ $m29, // Feb (28)
+ $m31, // Mar (31)
+ $m30, // Apr (30)
+ $m31, // May (31)
+ $m30, // Jun (30)
+ $m31, // Jul (31)
+ $m31, // Aug (31)
+ $m30, // Sep (30)
+ $m31, // Oct (31)
+ $m30, // Nov (30)
+ $m31, // Dec (31)
+ array_slice(
+ $m31,
+ 0,
+ 7
+ )
+ );
+
+ if (self::isLeapYearDate($dt)) {
+ return $mask;
+ } else {
+ if ($negative) {
+ $mask = array_merge(array_slice($mask, 0, 31), array_slice($mask, 32));
+ } else {
+ $mask = array_merge(array_slice($mask, 0, 59), array_slice($mask, 60));
+ }
+
+ return $mask;
+ }
+ }
+
+ public static function getMonthMask(\DateTimeInterface $dt)
+ {
+ if (self::isLeapYearDate($dt)) {
+ return array_merge(
+ array_fill(0, 31, 1), // Jan (31)
+ array_fill(0, 29, 2), // Feb (29)
+ array_fill(0, 31, 3), // Mar (31)
+ array_fill(0, 30, 4), // Apr (30)
+ array_fill(0, 31, 5), // May (31)
+ array_fill(0, 30, 6), // Jun (30)
+ array_fill(0, 31, 7), // Jul (31)
+ array_fill(0, 31, 8), // Aug (31)
+ array_fill(0, 30, 9), // Sep (30)
+ array_fill(0, 31, 10), // Oct (31)
+ array_fill(0, 30, 11), // Nov (30)
+ array_fill(0, 31, 12), // Dec (31)
+ array_fill(0, 7, 1)
+ );
+ } else {
+ return array_merge(
+ array_fill(0, 31, 1), // Jan (31)
+ array_fill(0, 28, 2), // Feb (28)
+ array_fill(0, 31, 3), // Mar (31)
+ array_fill(0, 30, 4), // Apr (30)
+ array_fill(0, 31, 5), // May (31)
+ array_fill(0, 30, 6), // Jun (30)
+ array_fill(0, 31, 7), // Jul (31)
+ array_fill(0, 31, 8), // Aug (31)
+ array_fill(0, 30, 9), // Sep (30)
+ array_fill(0, 31, 10), // Oct (31)
+ array_fill(0, 30, 11), // Nov (30)
+ array_fill(0, 31, 12), // Dec (31)
+ array_fill(0, 7, 1)
+ );
+ }
+ }
+
+ public static function getDateTimeByDayOfYear($dayOfYear, $year, \DateTimeZone $timezone)
+ {
+ $dtTmp = new \DateTime('now', $timezone);
+ $dtTmp = $dtTmp->setDate($year, 1, 1);
+ $dtTmp = $dtTmp->modify("+$dayOfYear day");
+
+ return $dtTmp;
+ }
+
+ public static function hasLeapYearBug()
+ {
+ $leapBugTest = \DateTime::createFromFormat('Y-m-d', '2016-03-21');
+ return $leapBugTest->format('z') != '80';
+ }
+
+ /**
+ * closure/goog/math/math.js:modulo
+ * Copyright 2006 The Closure Library Authors.
+ *
+ * The % operator in PHP returns the remainder of a / b, but differs from
+ * some other languages in that the result will have the same sign as the
+ * dividend. For example, -1 % 8 == -1, whereas in some other languages
+ * (such as Python) the result would be 7. This function emulates the more
+ * correct modulo behavior, which is useful for certain applications such as
+ * calculating an offset index in a circular list.
+ *
+ * @param int $a The dividend.
+ * @param int $b The divisor.
+ *
+ * @return int $a % $b where the result is between 0 and $b
+ * (either 0 <= x < $b
+ * or $b < x <= 0, depending on the sign of $b).
+ */
+ public static function pymod($a, $b)
+ {
+ $x = $a % $b;
+
+ // If $x and $b differ in sign, add $b to wrap the result to the correct sign.
+ return ($x * $b < 0) ? $x + $b : $x;
+ }
+
+ /**
+ * Alias method to determine if a date falls within a leap year.
+ *
+ * @param \DateTimeInterface $dt
+ *
+ * @return bool
+ */
+ public static function isLeapYearDate(\DateTimeInterface $dt)
+ {
+ return $dt->format('L') ? true : false;
+ }
+
+ /**
+ * Alias method to determine if a year is a leap year.
+ *
+ * @param int $year
+ *
+ * @return bool
+ */
+ public static function isLeapYear($year)
+ {
+ $isDivisBy4 = $year % 4 == 0 ? true : false;
+ $isDivisBy100 = $year % 100 == 0? true : false;
+ $isDivisBy400 = $year % 400 == 0 ? true : false;
+
+ // http://en.wikipedia.org/wiki/February_29
+ if ($isDivisBy100 && !$isDivisBy400) {
+ return false;
+ }
+
+ return $isDivisBy4;
+ }
+
+ /**
+ * Method to determine the day of the week from MO-SU.
+ *
+ * MO = Monday
+ * TU = Tuesday
+ * WE = Wednesday
+ * TH = Thursday
+ * FR = Friday
+ * SA = Saturday
+ * SU = Sunday
+ *
+ * @param \DateTimeInterface $dt
+ *
+ * @return string
+ */
+ public static function getDayOfWeekAsText(\DateTimeInterface $dt)
+ {
+ $dayOfWeek = $dt->format('w') - 1;
+
+ if ($dayOfWeek < 0) {
+ $dayOfWeek = 6;
+ }
+
+ $map = array('MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU');
+
+ return $map[$dayOfWeek];
+ }
+
+ /**
+ * Alias method to determine the day of the week from 0-6.
+ *
+ * 0 = Monday
+ * 1 = Tuesday
+ * 2 = Wednesday
+ * 3 = Thursday
+ * 4 = Friday
+ * 5 = Saturday
+ * 6 = Sunday
+ *
+ * @param \DateTimeInterface $dt
+ *
+ * @return int
+ */
+ public static function getDayOfWeek(\DateTimeInterface $dt)
+ {
+ $dayOfWeek = $dt->format('w') - 1;
+
+ if ($dayOfWeek < 0) {
+ $dayOfWeek = 6;
+ }
+
+ return $dayOfWeek;
+ }
+
+ /**
+ * Get the number of days in a year.
+ *
+ * @param \DateTimeInterface $dt
+ *
+ * @return int
+ */
+ public static function getYearLength(\DateTimeInterface $dt)
+ {
+ return self::isLeapYearDate($dt) ? 366 : 365;
+ }
+}