/** * convert timestamp to date array, default UTC or adjusted for offset/timezone * * @author Kjell-Inge Gustafsson, kigkonsult <*****@*****.**> * @since 2.15.1 - 2012-10-17 * @param mixed $timestamp * @param int $parno * @param string $wtz * @return array */ public static function _timestamp2date($timestamp, $parno = 6, $wtz = null) { if (is_array($timestamp)) { $tz = isset($timestamp['tz']) ? $timestamp['tz'] : $wtz; $timestamp = $timestamp['timestamp']; } $tz = isset($tz) ? $tz : $wtz; if (empty($tz) || 'Z' == $tz || 'GMT' == strtoupper($tz)) { $tz = 'UTC'; } elseif (iCalUtilityFunctions::_isOffset($tz)) { $offset = iCalUtilityFunctions::_tz2offset($tz); $tz = 'UTC'; } try { $d = new DateTime("@{$timestamp}"); // set UTC date if (isset($offset) && 0 != $offset) { // adjust for offset $d->modify($offset . ' seconds'); } elseif ('UTC' != $tz) { $d->setTimezone(new DateTimeZone($tz)); } // convert to local date $date = $d->format('Y-m-d-H-i-s'); unset($d); } catch (Exception $e) { $date = date('Y-m-d-H-i-s', $timestamp); } $date = explode('-', $date); $output = array('year' => $date[0], 'month' => $date[1], 'day' => $date[2]); if (3 != $parno) { $output['hour'] = $date[3]; $output['min'] = $date[4]; $output['sec'] = $date[5]; if ('UTC' == $tz && (!isset($offset) || 0 == $offset)) { $output['tz'] = 'Z'; } } return $output; }
/** * (very simple) conversion of a MS timezone to a PHP5 valid (Date-)timezone * matching (MS) UCT offset and time zone descriptors * * @author Kjell-Inge Gustafsson, kigkonsult <*****@*****.**> * @since 2.10.29 - 2012-01-11 * @param string $timezone, input/output variable reference * @return bool */ public static function ms2phpTZ(&$timezone) { if (!class_exists('DateTimeZone')) { return FALSE; } if (empty($timezone)) { return FALSE; } $search = str_replace('"', '', $timezone); $search = str_replace(array('GMT', 'gmt', 'utc'), 'UTC', $search); if ('(UTC' != substr($search, 0, 4)) { return FALSE; } if (FALSE === ($pos = strpos($search, ')'))) { return FALSE; } $pos = strpos($search, ')'); $searchOffset = substr($search, 4, $pos - 4); $searchOffset = iCalUtilityFunctions::_tz2offset(str_replace(':', '', $searchOffset)); while (' ' == substr($search, $pos + 1)) { $pos += 1; } $searchText = trim(str_replace(array('(', ')', '&', ',', ' '), ' ', substr($search, $pos + 1))); $searchWords = explode(' ', $searchText); $timezone_abbreviations = DateTimeZone::listAbbreviations(); $hits = array(); foreach ($timezone_abbreviations as $name => $transitions) { foreach ($transitions as $cnt => $transition) { if (empty($transition['offset']) || empty($transition['timezone_id']) || $transition['offset'] != $searchOffset) { continue; } $cWords = explode('/', $transition['timezone_id']); $cPrio = $hitCnt = $rank = 0; foreach ($cWords as $cWord) { if (empty($cWord)) { continue; } $cPrio += 1; $sPrio = 0; foreach ($searchWords as $sWord) { if (empty($sWord) || 'time' == strtolower($sWord)) { continue; } $sPrio += 1; if (strtolower($cWord) == strtolower($sWord)) { $hitCnt += 1; $rank += $cPrio + $sPrio; } else { $rank += 10; } } } if (0 < $hitCnt) { $hits[$rank][] = $transition['timezone_id']; } } } unset($timezone_abbreviations); if (empty($hits)) { return FALSE; } ksort($hits); foreach ($hits as $rank => $tzs) { if (!empty($tzs)) { $timezone = reset($tzs); return TRUE; } } return FALSE; }
/** * Returns an array containing time zone data from vtimezone standard/daylight instances * * @param object $vtzc an iCalcreator calendar standard/daylight instance * @return array time zone data; array before(offsetHis, offsetSec), array after(offsetHis, offsetSec, tzname) * */ function expandTimezoneDates($vtzc) { $tzdates = array(); // prepare time zone "description" to attach to each change $tzbefore = array(); $tzbefore['offsetHis'] = $vtzc->getProperty('tzoffsetfrom'); $tzbefore['offsetSec'] = iCalUtilityFunctions::_tz2offset($tzbefore['offsetHis']); if ('-' != substr((string) $tzbefore['offsetSec'], 0, 1) && '+' != substr((string) $tzbefore['offsetSec'], 0, 1)) { $tzbefore['offsetSec'] = '+' . $tzbefore['offsetSec']; } $tzafter = array(); $tzafter['offsetHis'] = $vtzc->getProperty('tzoffsetto'); $tzafter['offsetSec'] = iCalUtilityFunctions::_tz2offset($tzafter['offsetHis']); if ('-' != substr((string) $tzafter['offsetSec'], 0, 1) && '+' != substr((string) $tzafter['offsetSec'], 0, 1)) { $tzafter['offsetSec'] = '+' . $tzafter['offsetSec']; } if (FALSE === ($tzafter['tzname'] = $vtzc->getProperty('tzname'))) { $tzafter['tzname'] = $tzafter['offsetHis']; } // find out where to start from $dtstart = $vtzc->getProperty('dtstart'); $dtstarttimestamp = mktime($dtstart['hour'], $dtstart['min'], $dtstart['sec'], $dtstart['month'], $dtstart['day'], $dtstart['year']); if (!isset($dtstart['unparsedtext'])) { // ?? $dtstart['unparsedtext'] = sprintf('%04d%02d%02dT%02d%02d%02d', $dtstart['year'], $dtstart['month'], $dtstart['day'], $dtstart['hour'], $dtstart['min'], $dtstart['sec']); } if ($dtstarttimestamp == 0) { // it seems that the dtstart string may not have parsed correctly // let's set a timestamp starting from 1902, using the time part of the original string // so that the time will change at the right time of day // at worst we'll get midnight again $origdtstartsplit = explode('T', $dtstart['unparsedtext']); $dtstarttimestamp = strtotime("19020101", 0); $dtstarttimestamp = strtotime($origdtstartsplit[1], $dtstarttimestamp); } // the date (in dtstart and opt RDATE/RRULE) is ALWAYS LOCAL (not utc!!), adjust from 'utc' to 'local' timestamp $diff = -1 * $tzbefore['offsetSec']; $dtstarttimestamp += $diff; // add this (start) change to the array of changes $tzdates[] = array('timestamp' => $dtstarttimestamp, 'tzbefore' => $tzbefore, 'tzafter' => $tzafter); $datearray = getdate($dtstarttimestamp); // save original array to use time parts, because strtotime (used below) apparently loses the time $changetime = $datearray; // generate dates according to an RRULE line $rrule = $vtzc->getProperty('rrule'); if (is_array($rrule)) { if ($rrule['FREQ'] == 'YEARLY') { // calculate transition dates starting from DTSTART $offsetchangetimestamp = $dtstarttimestamp; // calculate transition dates until 10 years in the future $stoptimestamp = strtotime("+10 year", time()); // if UNTIL is set, calculate until then (however far ahead) if (isset($rrule['UNTIL']) && $rrule['UNTIL'] != '') { $stoptimestamp = mktime($rrule['UNTIL']['hour'], $rrule['UNTIL']['min'], $rrule['UNTIL']['sec'], $rrule['UNTIL']['month'], $rrule['UNTIL']['day'], $rrule['UNTIL']['year']); } $count = 0; $stopcount = isset($rrule['COUNT']) ? $rrule['COUNT'] : 0; $daynames = array('SU' => 'Sunday', 'MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday'); // repeat so long as we're between DTSTART and UNTIL, or we haven't prepared COUNT dates while ($offsetchangetimestamp < $stoptimestamp && ($stopcount == 0 || $count < $stopcount)) { // break up the timestamp into its parts $datearray = getdate($offsetchangetimestamp); if (isset($rrule['BYMONTH']) && $rrule['BYMONTH'] != 0) { // set the month $datearray['mon'] = $rrule['BYMONTH']; } if (isset($rrule['BYMONTHDAY']) && $rrule['BYMONTHDAY'] != 0) { // set specific day of month $datearray['mday'] = $rrule['BYMONTHDAY']; } elseif (is_array($rrule['BYDAY'])) { // find the Xth WKDAY in the month // the starting point for this process is the first of the month set above $datearray['mday'] = 1; // turn $datearray as it is now back into a timestamp $offsetchangetimestamp = mktime($datearray['hours'], $datearray['minutes'], $datearray['seconds'], $datearray['mon'], $datearray['mday'], $datearray['year']); if ($rrule['BYDAY'][0] > 0) { // to find Xth WKDAY in month, we find last WKDAY in month before // we do that by finding first WKDAY in this month and going back one week // then we add X weeks (below) $offsetchangetimestamp = strtotime($daynames[$rrule['BYDAY']['DAY']], $offsetchangetimestamp); $offsetchangetimestamp = strtotime("-1 week", $offsetchangetimestamp); } else { // to find Xth WKDAY before the end of the month, we find the first WKDAY in the following month // we do that by going forward one month and going to WKDAY there // then we subtract X weeks (below) $offsetchangetimestamp = strtotime("+1 month", $offsetchangetimestamp); $offsetchangetimestamp = strtotime($daynames[$rrule['BYDAY']['DAY']], $offsetchangetimestamp); } // now move forward or back the appropriate number of weeks, into the month we want $offsetchangetimestamp = strtotime($rrule['BYDAY'][0] . " week", $offsetchangetimestamp); $datearray = getdate($offsetchangetimestamp); } // convert the date parts back into a timestamp, setting the time parts according to the // original time data which we stored $offsetchangetimestamp = mktime($changetime['hours'], $changetime['minutes'], $changetime['seconds'] + $diff, $datearray['mon'], $datearray['mday'], $datearray['year']); // add this change to the array of changes $tzdates[] = array('timestamp' => $offsetchangetimestamp, 'tzbefore' => $tzbefore, 'tzafter' => $tzafter); // update counters (timestamp and count) $offsetchangetimestamp = strtotime("+" . (isset($rrule['INTERVAL']) && $rrule['INTERVAL'] != 0 ? $rrule['INTERVAL'] : 1) . " year", $offsetchangetimestamp); $count += 1; } } } // generate dates according to RDATE lines while ($rdates = $vtzc->getProperty('rdate')) { if (is_array($rdates)) { foreach ($rdates as $rdate) { // convert the explicit change date to a timestamp $offsetchangetimestamp = mktime($rdate['hour'], $rdate['min'], $rdate['sec'] + $diff, $rdate['month'], $rdate['day'], $rdate['year']); // add this change to the array of changes $tzdates[] = array('timestamp' => $offsetchangetimestamp, 'tzbefore' => $tzbefore, 'tzafter' => $tzafter); } } } return $tzdates; }
private static function date2timestamp($datetime, $tz = null) { if (!isset($datetime['hour'])) { $datetime['hour'] = '0'; } if (!isset($datetime['min'])) { $datetime['min'] = '0'; } if (!isset($datetime['sec'])) { $datetime['sec'] = '0'; } foreach ($datetime as $dkey => $dvalue) { if ('tz' != $dkey) { $datetime[$dkey] = (int) $dvalue; } } if ($tz) { $datetime['tz'] = $tz; } $offset = isset($datetime['tz']) && '' < trim($datetime['tz']) ? iCalUtilityFunctions::_tz2offset($datetime['tz']) : 0; return gmmktime($datetime['hour'], $datetime['min'], $datetime['sec'] + $offset, $datetime['month'], $datetime['day'], $datetime['year']); }
/** * creates formatted output for calendar component property data value type date/date-time * * @author Kjell-Inge Gustafsson <*****@*****.**> * @since 2.4.8 - 2008-10-30 * @param array $datetime * @param int $parno, optional, default 6 * @return string */ public static function _format_date_time($datetime, $parno = 6) { if (!isset($datetime['year']) && !isset($datetime['month']) && !isset($datetime['day']) && !isset($datetime['hour']) && !isset($datetime['min']) && !isset($datetime['sec'])) { return; } $output = null; // if( !isset( $datetime['day'] )) { $o=''; foreach($datetime as $k=>$v) {if(is_array($v)) $v=implode('-',$v);$o.=" $k=>$v";} echo " day SAKNAS : $o <br />\n"; } foreach ($datetime as $dkey => &$dvalue) { if ('tz' != $dkey) { $dvalue = (int) $dvalue; } } $output = date('Ymd', mktime(0, 0, 0, $datetime['month'], $datetime['day'], $datetime['year'])); if (isset($datetime['hour']) || isset($datetime['min']) || isset($datetime['sec']) || isset($datetime['tz'])) { if (isset($datetime['tz']) && !isset($datetime['hour'])) { $datetime['hour'] = 0; } if (isset($datetime['hour']) && !isset($datetime['min'])) { $datetime['min'] = 0; } if (isset($datetime['hour']) && isset($datetime['min']) && !isset($datetime['sec'])) { $datetime['sec'] = 0; } $date = mktime($datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year']); $output .= date('\\THis', $date); if (isset($datetime['tz']) && '' < trim($datetime['tz'])) { $datetime['tz'] = trim($datetime['tz']); if ('Z' == $datetime['tz']) { $output .= 'Z'; } $offset = iCalUtilityFunctions::_tz2offset($datetime['tz']); if (0 != $offset) { $date = mktime($datetime['hour'], $datetime['min'], $datetime['sec'] + $offset, $datetime['month'], $datetime['day'], $datetime['year']); $output = date('Ymd\\THis\\Z', $date); } } elseif (7 == $parno) { $output .= 'Z'; } } return $output; }