Copyright 2003-2016 Horde LLC (http://www.horde.org/) See the enclosed file COPYING for license information (LGPL). If you did not receive this file, see http://www.horde.org/licenses/lgpl21.
Author: Mike Cochrane (mike@graftonhall.co.nz)
Inheritance: extends Horde_Icalendar
Exemple #1
0
 /**
  * Exports this zone to a VTIMEZONE component.
  *
  * @return Horde_Icalendar_Vtimezone  A VTIMEZONE component representing
  *                                    this timezone.
  * @throws Horde_Timezone_Exception
  */
 public function toVtimezone()
 {
     if (!count($this->_info)) {
         throw new Horde_Timezone_Exception('No rules found for timezone ' . $this->_name);
     }
     $tz = new Horde_Icalendar_Vtimezone();
     $tz->setAttribute('TZID', $this->_name);
     if (count($this->_info[0]) <= 3) {
         // Zone has no start or end date, but DAYLIGHT and STANDARD
         // components are required to have a DTSTART attribute [RFC
         // 5545 3.8.2.4].
         return $tz;
     }
     $startDate = $this->_getDate(0);
     $startOffset = $this->_getOffset(0);
     for ($i = 1, $c = count($this->_info); $i < $c; $i++) {
         $name = $this->_info[$i][2];
         $endDate = count($this->_info[$i]) > 3 ? $this->_getDate($i) : null;
         if ($this->_info[$i][1] == '-') {
             // Standard time.
             $component = new Horde_Icalendar_Standard();
         } elseif (preg_match('/\\d+(:(\\d+))?/', $this->_info[$i][1])) {
             // Indiviual rule not matching any ruleset.
             $component = new Horde_Icalendar_Daylight();
         } else {
             // Represented by a ruleset.
             $startOffset = $this->_getOffset($i);
             $this->_tz->getRule($this->_info[$i][1])->addRules($tz, $this->_name, $name, $startOffset, $startDate, $endDate);
             $startDate = $endDate;
             // Continue, because addRules() already adds the
             // component to $tz.
             continue;
         }
         $component->setAttribute('DTSTART', $startDate);
         $component->setAttribute('TZOFFSETFROM', $startOffset);
         $startOffset = $this->_getOffset($i);
         $component->setAttribute('TZOFFSETTO', $startOffset);
         $component->setAttribute('TZNAME', $name);
         $tz->addComponent($component);
     }
     return $tz;
 }
Exemple #2
0
 /**
  * Adds rules from this ruleset to a VTIMEZONE component.
  *
  * @param Horde_Icalendar_Vtimezone $tz  A VTIMEZONE component.
  * @param string $tzid                   The timezone ID of the component.
  * @param string $name                   A timezone name abbreviation.
  *                                       May contain a placeholder that is
  *                                       replaced the Rules' "Letter(s)"
  *                                       entry.
  * @param array $startOffset             An offset hash describing the
  *                                       base offset of a timezone.
  * @param Horde_Date $start              Start of the period to add rules
  *                                       for.
  * @param Horde_Date $end                End of the period to add rules
  *                                       for.
  */
 public function addRules(Horde_Icalendar_Vtimezone $tz, $tzid, $name, $startOffset, Horde_Date $start, Horde_Date $end = null)
 {
     $offset = $startOffset;
     foreach ($this->_rules as $rule) {
         $year = $rule[3];
         if ($year[0] == 'o') {
             // TO is "only"
             $rule[3] = $rule[2];
         }
         if ($rule[3][0] != 'm' && $rule[3] < $start->year) {
             // TO is not maximum and is before the searched period
             continue;
         }
         if ($end && $rule[2][0] != 'm' && $rule[2] > $end->year) {
             // FROM is not "minimum" and is after the searched period
             break;
         }
         if ($rule[2][0] != 'm' && $rule[2] < $start->year) {
             $rule[2] = $start->year;
         }
         if ($rule[8] == 0) {
             $component = new Horde_Icalendar_Standard();
             $component->setAttribute('TZOFFSETFROM', $offset);
             $component->setAttribute('TZOFFSETTO', $startOffset);
             $offset = $startOffset;
         } else {
             $component = new Horde_Icalendar_Daylight();
             $component->setAttribute('TZOFFSETFROM', $offset);
             $offset = $this->_getOffset($startOffset, $rule[8]);
             $component->setAttribute('TZOFFSETTO', $offset);
         }
         $month = Horde_Timezone::getMonth($rule[5]);
         // Retrieve time of rule start.
         preg_match('/(\\d+)(?::(\\d+))?(?::(\\d+))?(w|s|u)?/', $rule[7], $match);
         if (!isset($match[2])) {
             $match[2] = 0;
         }
         if ($rule[2] == $rule[3] && preg_match('/^\\d+$/', $rule[6])) {
             // Rule lasts only for a single year and starts on a specific
             // date.
             $rdate = new Horde_Date(array('year' => $rule[2], 'month' => Horde_Timezone::getMonth($rule[5]), 'mday' => $rule[6], 'hour' => $match[1], 'min' => $match[2], 'sec' => 0));
             $component->setAttribute('DTSTART', $rdate);
         } elseif (substr($rule[6], 0, 4) == 'last') {
             // Rule starts on the last of a certain weekday of the month.
             $weekday = $this->_weekdays[substr($rule[6], 4, 3)];
             $last = new Horde_Date(array('year' => $rule[2], 'month' => $month, 'mday' => Horde_Date_Utils::daysInMonth($month, $rule[2]), 'hour' => $match[1], 'min' => $match[2], 'sec' => 0));
             while ($last->dayOfWeek() != $weekday) {
                 $last->mday--;
             }
             $component->setAttribute('DTSTART', $last);
             if ($rule[3][0] == 'm') {
                 $until = '';
             } else {
                 $last = new Horde_Date(array('year' => $rule[3], 'month' => $month, 'mday' => Horde_Date_Utils::daysInMonth($month, $rule[2]), 'hour' => $match[1], 'min' => $match[2], 'sec' => 0), $tzid);
                 while ($last->dayOfWeek() != $weekday) {
                     $last->mday--;
                 }
                 $last->setTimezone('UTC');
                 $until = ';UNTIL=' . $last->format('Ymd\\THIs') . 'Z';
             }
             $component->setAttribute('RRULE', 'FREQ=YEARLY;BYDAY=-1' . Horde_String::upper(substr($rule[6], 4, 2)) . ';BYMONTH=' . $month . $until);
         } elseif (strpos($rule[6], '>=')) {
             // Rule starts on a certain weekday after a certain day of
             // month.
             list($weekday, $day) = explode('>=', $rule[6]);
             $weekdayInt = $this->_weekdays[substr($weekday, 0, 3)];
             $first = new Horde_Date(array('year' => $rule[2], 'month' => $month, 'mday' => $day, 'hour' => $match[1], 'min' => $match[2], 'sec' => 0));
             while ($first->dayOfWeek() != $weekdayInt) {
                 $first->mday++;
             }
             $component->setAttribute('DTSTART', $first);
             if ($rule[3][0] == 'm') {
                 $until = '';
             } else {
                 $last = new Horde_Date(array('year' => $rule[3], 'month' => $month, 'mday' => $day, 'hour' => $match[1], 'min' => $match[2], 'sec' => 0), $tzid);
                 while ($last->dayOfWeek() != $weekday) {
                     $last->mday++;
                 }
                 $last->setTimezone('UTC');
                 $until = ';UNTIL=' . $last->format('Ymd\\THIs') . 'Z';
             }
             for ($days = array(), $i = $day, $lastDay = min(Horde_Date_Utils::daysInMonth($month, $rule[2]), $i + 6); $day > 1 && $i <= $lastDay; $i++) {
                 $days[] = $i;
             }
             $component->setAttribute('RRULE', 'FREQ=YEARLY;BYMONTH=' . $month . ($days ? ';BYMONTHDAY=' . implode(',', $days) : '') . ';BYDAY=1' . Horde_String::upper(substr($weekday, 0, 2)) . $until);
         } elseif (strpos($rule[6], '<=')) {
             // Rule starts on a certain weekday before a certain day of
             // month.
             list($weekday, $day) = explode('>=', $rule[6]);
             $weekdayInt = $this->_weekdays[substr($weekday, 0, 3)];
             $last = new Horde_Date(array('year' => $rule[2], 'month' => $month, 'mday' => $day, 'hour' => $match[1], 'min' => $match[2], 'sec' => 0));
             while ($last->dayOfWeek() != $weekdayInt) {
                 $last->mday--;
             }
             $component->setAttribute('DTSTART', $last);
             if ($rule[3][0] == 'm') {
                 $until = '';
             } else {
                 $last = new Horde_Date(array('year' => $rule[3], 'month' => $month, 'mday' => $day, 'hour' => $match[1], 'min' => $match[2], 'sec' => 0), $tzid);
                 while ($last->dayOfWeek() != $weekday) {
                     $last->mday--;
                 }
                 $last->setTimezone('UTC');
                 $until = ';UNTIL=' . $last->format('Ymd\\THIs') . 'Z';
             }
             for ($days = array(), $i = 1; $i <= $day; $i++) {
                 $days[] = $i;
             }
             $component->setAttribute('RRULE', 'FREQ=YEARLY;BYMONTH=' . $month . ';BYMONTHDAY=' . implode(',', $days) . ';BYDAY=-1' . Horde_String::upper(substr($weekday, 0, 2)) . $until);
         }
         $component->setAttribute('TZNAME', sprintf($name, $rule[9]));
         $tz->addComponent($component);
     }
 }
Exemple #3
0
 /**
  * Adds rules from this ruleset to a VTIMEZONE component.
  *
  * @param Horde_Icalendar_Vtimezone $tz  A VTIMEZONE component.
  * @param string $tzid                   The timezone ID of the component.
  * @param string $name                   A timezone name abbreviation.
  *                                       May contain a placeholder that is
  *                                       replaced the Rules' "Letter(s)"
  *                                       entry.
  * @param array $startOffset             An offset hash describing the
  *                                       base offset of a timezone.
  * @param Horde_Date $start              Start of the period to add rules
  *                                       for.
  * @param Horde_Date $end                End of the period to add rules
  *                                       for.
  */
 public function addRules(Horde_Icalendar_Vtimezone $tz, $tzid, $name, $startOffset, Horde_Date $start, Horde_Date $end = null)
 {
     foreach ($this->_rules as $ruleNo => $rule) {
         // The rule items are:
         // 0: "Rule"
         // 1: The rule name
         // 2: The start year or "minimum"
         // 3: The end year or "only" if only at the start year or "maximum"
         // 4: Type, whatever that means (unused)
         // 5: The start month
         // 6: The start day, either specific or as a rule
         // 7: The start time
         // 8: The offset to the base time
         // 9: The time name abbreviation
         $year = $rule[3];
         if ($year[0] == 'o') {
             // TO is "only"
             $rule[3] = $rule[2];
         }
         if ($rule[3][0] != 'm' && $rule[3] < $start->year) {
             // TO is not "maximum" and is before the searched period
             continue;
         }
         if ($end && $rule[2][0] != 'm' && $rule[2] > $end->year) {
             // FROM is not "minimum" and is after the searched period
             break;
         }
         if ($rule[2][0] != 'm' && $rule[2] < $start->year) {
             $rule[2] = $start->year;
         }
         // The month of rule start.
         $month = Horde_Timezone::getMonth($rule[5]);
         // The time of rule start.
         preg_match('/(\\d+)(?::(\\d+))?(?::(\\d+))?([wsguz])?/', $rule[7], $match);
         $hour = $match[1];
         $minute = isset($match[2]) ? $match[2] : 0;
         if (!isset($match[4])) {
             $modifier = 'w';
         } elseif ($match[4] == 'g' || $match[4] == 'z') {
             $modifier = 'u';
         } else {
             $modifier = $match[4];
         }
         // Find the start date.
         $first = $this->_getFirstMatch($rule, $rule[2]);
         $first->hour = $hour;
         $first->min = $minute;
         $previousOffset = $this->_findPreviousOffset($first, $ruleNo, $startOffset);
         if ($rule[8] == 0) {
             $component = new Horde_Icalendar_Standard();
             $component->setAttribute('TZOFFSETFROM', $previousOffset);
             $component->setAttribute('TZOFFSETTO', $startOffset);
         } else {
             $component = new Horde_Icalendar_Daylight();
             $component->setAttribute('TZOFFSETFROM', $previousOffset);
             $component->setAttribute('TZOFFSETTO', $this->_getOffset($startOffset, $rule[8]));
         }
         switch ($modifier) {
             case 's':
                 $first->hour += ($previousOffset['ahead'] ? 1 : -1) * $previousOffset['hour'] - ($startOffset['ahead'] ? 1 : -1) * $startOffset['hour'];
                 $first->min += ($previousOffset['ahead'] ? 1 : -1) * $previousOffset['minute'] - ($startOffset['ahead'] ? 1 : -1) * $startOffset['minute'];
                 break;
             case 'u':
                 $first->hour += ($previousOffset['ahead'] ? 1 : -1) * $previousOffset['hour'];
                 $first->min += ($previousOffset['ahead'] ? 1 : -1) * $previousOffset['minute'];
                 break;
         }
         $component->setAttribute('DTSTART', $first);
         // Find the end date.
         if ($rule[3][0] == 'm') {
             $until = '';
         } else {
             $last = $this->_getFirstMatch($rule, $rule[3]);
             $last->hour = $hour;
             $last->min = $minute;
             switch ($modifier) {
                 case 's':
                     $last->hour -= ($startOffset['ahead'] ? 1 : -1) * $startOffset['hour'];
                     $last->min -= ($startOffset['ahead'] ? 1 : -1) * $startOffset['minute'];
                     break;
                 case 'w':
                     $last->hour -= ($previousOffset['ahead'] ? 1 : -1) * $previousOffset['hour'];
                     $last->min -= ($previousOffset['ahead'] ? 1 : -1) * $previousOffset['minute'];
                     break;
             }
             $until = ';UNTIL=' . $last->format('Ymd\\THis') . 'Z';
         }
         if ($rule[2] != $rule[3]) {
             if (preg_match('/^\\d+$/', $rule[6])) {
                 // Rule starts on a specific date.
                 $component->setAttribute('RRULE', 'FREQ=YEARLY;BYMONTH=' . $month . ';BYMONTHDAY=' . $rule[6] . $until);
             } elseif (substr($rule[6], 0, 4) == 'last') {
                 // Rule starts on the last of a certain weekday of the month.
                 $component->setAttribute('RRULE', 'FREQ=YEARLY;BYDAY=-1' . Horde_String::upper(substr($rule[6], 4, 2)) . ';BYMONTH=' . $month . $until);
             } elseif (strpos($rule[6], '>=')) {
                 // Rule starts on a certain weekday after a certain day of
                 // month.
                 list($weekday, $day) = explode('>=', $rule[6]);
                 for ($days = array(), $i = $day, $lastDay = min(Horde_Date_Utils::daysInMonth($month, $rule[2]), $i + 6); $day > 1 && $i <= $lastDay; $i++) {
                     $days[] = $i;
                 }
                 $component->setAttribute('RRULE', 'FREQ=YEARLY;BYMONTH=' . $month . ($days ? ';BYMONTHDAY=' . implode(',', $days) : '') . ';BYDAY=1' . Horde_String::upper(substr($weekday, 0, 2)) . $until);
             } elseif (strpos($rule[6], '<=')) {
                 // Rule starts on a certain weekday before a certain day of
                 // month.
                 for ($days = array(), $i = 1; $i <= $day; $i++) {
                     $days[] = $i;
                 }
                 $component->setAttribute('RRULE', 'FREQ=YEARLY;BYMONTH=' . $month . ';BYMONTHDAY=' . implode(',', $days) . ';BYDAY=-1' . Horde_String::upper(substr($weekday, 0, 2)) . $until);
             } else {
                 continue;
             }
         }
         $component->setAttribute('TZNAME', sprintf($name, $rule[9]));
         $tz->addComponent($component);
     }
 }