"Using VTIMEZONE component from new calendar_timezones class (imported sqlite DB from Lighting) for exports and importing TZID from iCals.

Horde Code already uses VTIMEZONE component to return times in servertime, no need to change anything there."
This commit is contained in:
Ralf Becker 2009-11-10 15:08:35 +00:00
parent 90d5815dfa
commit 85bf743434

View File

@ -198,20 +198,18 @@ class calendar_ical extends calendar_boupdate
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang'])); strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
$vcal->setAttribute('VERSION', $version); $vcal->setAttribute('VERSION', $version);
$vcal->setAttribute('METHOD', $method); $vcal->setAttribute('METHOD', $method);
$serverTZ = false;
if (!is_array($events)) $events = array($events); if (!is_array($events)) $events = array($events);
while (($event = array_pop($events))) $vtimezones_added = array();
foreach($events as $event)
{ {
if (strpos($this->productName, 'palmos')) if (strpos($this->productName, 'palmos') !== false)
{ {
$utc = false;
$date_format = 'ts'; $date_format = 'ts';
} }
else else
{ {
$utc = true;
$date_format = 'server'; $date_format = 'server';
} }
if (!is_array($event) if (!is_array($event)
@ -236,34 +234,31 @@ class calendar_ical extends calendar_boupdate
if ($this->log) error_log(__FILE__.'('.__LINE__.'): '.__METHOD__.' '.array2string($event)."\n",3,$this->logfile); if ($this->log) error_log(__FILE__.'('.__LINE__.'): '.__METHOD__.' '.array2string($event)."\n",3,$this->logfile);
if (!$serverTZ // for palmos we have to use user-time and NO timezone
&& $event['recur_type'] != MCAL_RECUR_NONE if (strpos($this->productName, 'palmos') !== false)
&& date('e', $event['start']) != 'UTC')
{ {
if ($event['recur_enddate']) $tzid = null;
}
// check if tzid of event (not only recuring ones) is already added to export
elseif (($tzid = $event['tzid']) && $tzid != 'UTC' && !in_array($tzid,$vtimezones_added))
{ {
$startDST = date('I', $event['start']); // check if we have vtimezone component data for tzid of event, if not default to user timezone (default to server tz)
$finalDST = date('I', $event['recur_enddate']); if (!($vtimezone = calendar_timezones::tz2id($tzid,'component')))
// Different DST or more than half a year?
if ($startDST != $finalDST ||
($event['recur_enddate'] - $event['start']) > 15778800)
{ {
$utc = false; error_log(__METHOD__."() unknown TZID='$tzid', defaulting to user timezone '".egw_time::$user_timezone->getName()."'!");
$serverTZ = true; $vtimezone = calendar_timezones::tz2id($tzid=egw_time::$user_timezone->getName(),'component');
}
//error_log("in_array('$tzid',\$vtimezones_added)=".array2string(in_array($tzid,$vtimezones_added)).", component=$vtimezone");;
if (!in_array($tzid,$vtimezones_added))
{
// $vtimezone is a string with a single VTIMEZONE component, afaik Horde_iCalendar can not add it directly
// --> we have to parse it and let Horde_iCalendar add it again
$horde_vtimezone = Horde_iCalendar::newComponent('VTIMEZONE',$container=false);
$horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE');
$vcal->addComponent($horde_vtimezone);
$vtimezones_added[] = $tzid;
} }
} }
else
{
$utc = false;
$serverTZ = true;
}
if ($serverTZ)
{
// Add only one instance
$serverTZ = $this->generate_vtimezone($event, $vcal);
}
}
if ($this->productManufacturer != 'file' && $this->uidExtension) if ($this->productManufacturer != 'file' && $this->uidExtension)
{ {
// Append UID to DESCRIPTION // Append UID to DESCRIPTION
@ -347,15 +342,7 @@ class calendar_ical extends calendar_boupdate
break; break;
case 'DTSTART': case 'DTSTART':
if ($utc) $attributes['DTSTART'] = self::getDateTime($event['start'],$tzid,$parameters['DTSTART']);
{
$attributes['DTSTART'] = $event['start'];
}
else
{
$attributes['DTSTART'] = date('Ymd\THis', $event['start']);
if ($serverTZ) $parameters['DTSTART']['TZID'] = $serverTZ;
}
break; break;
case 'DTEND': case 'DTEND':
@ -373,15 +360,7 @@ class calendar_ical extends calendar_boupdate
} }
else else
{ {
if ($utc) $attributes['DTEND'] = self::getDateTime($event['end'],$tzid,$parameters['DTEND']);
{
$attributes['DTEND'] = $event['end'];
}
else
{
$attributes['DTEND'] = date('Ymd\THis', $event['end']);
if ($serverTZ) $parameters['DTEND']['TZID'] = $serverTZ;
}
} }
break; break;
@ -516,18 +495,13 @@ class calendar_ical extends calendar_boupdate
else else
{ {
$value_type = 'DATE-TIME'; $value_type = 'DATE-TIME';
if (!$utc) foreach ($days as &$timestamp)
{ {
foreach ($days as $id => $timestamp) $timestamp = self::getDateTime($timestamp,$tzid,$parameters['EXDATE']);
{
$days[$id] = date('Ymd\THis', $timestamp);
}
} }
} }
$attributes['EXDATE'] = ''; $attributes['EXDATE'] = '';
$values['EXDATE'] = $days; $values['EXDATE'] = $days;
if ($serverTZ) $parameters['EXDATE']['TZID'] = $serverTZ;
$parameters['EXDATE']['VALUE'] = $value_type; $parameters['EXDATE']['VALUE'] = $value_type;
} }
break; break;
@ -575,15 +549,7 @@ class calendar_ical extends calendar_boupdate
} }
else else
{ {
if ($utc) $attributes[$icalFieldName] = self::getDateTime($recur_date,$tzid,$parameters[$icalFieldName]);
{
$attributes[$icalFieldName] = $recur_date;
}
else
{
$attributes[$icalFieldName] = date('Ymd\THis', $recur_date);
if ($serverTZ) $parameters[$icalFieldName]['TZID'] = $serverTZ;
}
} }
} }
elseif ($event['recurrence'] && $event['reference']) elseif ($event['recurrence'] && $event['reference'])
@ -603,15 +569,7 @@ class calendar_ical extends calendar_boupdate
} }
else else
{ {
if ($utc) $attributes[$icalFieldName] = self::getDateTime($recur_date,$tzid,$parameters[$icalFieldName]);
{
$attributes[$icalFieldName] = $event['recurrence'];
}
else
{
$attributes[$icalFieldName] = date('Ymd\THis', $event['recurrence']);
if ($serverTZ) $parameters[$icalFieldName]['TZID'] = $serverTZ;
}
} }
unset($revent); unset($revent);
} }
@ -693,18 +651,8 @@ class calendar_ical extends calendar_boupdate
if ($version == '1.0') if ($version == '1.0')
{ {
if ($utc) $attributes['DALARM'] = self::getDateTime($alarmData['time'],$tzid,$parameters['DALARM']);
{ $attributes['AALARM'] = self::getDateTime($alarmData['time'],$tzid,$parameters['AALARM']);
$attributes['DALARM'] = $alarmData['time'];
$attributes['AALARM'] = $alarmData['time'];
}
else
{
$attributes['DALARM'] = date('Ymd\THis', $alarmData['time']);
if ($serverTZ) $parameters['DALARM']['TZID'] = $serverTZ;
$attributes['AALARM'] = date('Ymd\THis', $alarmData['time']);
if ($serverTZ) $parameters['AALARM']['TZID'] = $serverTZ;
}
// lets take only the first alarm // lets take only the first alarm
break; break;
} }
@ -735,15 +683,7 @@ class calendar_ical extends calendar_boupdate
else else
{ {
$params = array('VALUE' => 'DATE-TIME'); $params = array('VALUE' => 'DATE-TIME');
if ($utc) $value = self::getDateTime($alarmData['time'],$tzid,$params);
{
$value = $alarmData['time'];
}
else
{
$value = date('Ymd\THis', $alarmData['time']);
if ($serverTZ) $params['TZID'] = $serverTZ;
}
$valarm->setAttribute('TRIGGER', $value, $params); $valarm->setAttribute('TRIGGER', $value, $params);
} }
@ -790,6 +730,36 @@ class calendar_ical extends calendar_boupdate
} }
/**
* Get DateTime value for a given time and timezone
*
* @param int|string|DateTime $time in server-time as returned by calendar_bo for $data_format='server'
* @param string $tzid TZID of event or 'UTC' or NULL for palmos timestamps in usertime
* @param array &$params=null parameter array to set TZID
* @return mixed attribute value to set: integer timestamp if $tzid == 'UTC' otherwise Ymd\THis string IN $tzid
*/
static function getDateTime($time,$tzid,array &$params=null)
{
if (empty($tzid) || $tzid == 'UTC')
{
return egw_time::to($time,'ts');
}
if (!is_a($time,'DateTime'))
{
$time = new egw_time($time,egw_time::$server_timezone);
}
static $timezone;
static $timezone_tzid;
if (is_null($timezone) || $timezone_tzid != $tzid)
{
$timezone = new DateTimeZone($timezone_tzid = $tzid);
}
$time->setTimezone($timezone);
$params['TZID'] = $tzid;
return $time->format('Ymd\THis');
}
/** /**
* Import an iCal * Import an iCal
* *
@ -1531,6 +1501,21 @@ class calendar_ical extends calendar_boupdate
} }
$dtstart_ts = is_numeric($attributes['value']) ? $attributes['value'] : $this->date2ts($attributes['value']); $dtstart_ts = is_numeric($attributes['value']) ? $attributes['value'] : $this->date2ts($attributes['value']);
$vcardData['start'] = $dtstart_ts; $vcardData['start'] = $dtstart_ts;
// import TZID, if PHP understands it (we only care about TZID of starttime, as we store only a TZID for the whole event)
if (!empty($attributes['params']['TZID']))
{
try
{
$tz = new DateTimeZone($attributes['params']['TZID']);
$event['tzid'] = $tz->getName();
}
catch(Exception $e)
{
error_log(__METHOD__."() unknown TZID='{$attributes['params']['TZID']}', defaulting to user timezone '".egw_time::$user_timezone->getName()."'!");
$event['tzid'] = egw_time::$user_timezone->getName(); // default to user timezone
}
}
break; break;
case 'DTEND': case 'DTEND':
$dtend_ts = is_numeric($attributes['value']) ? $attributes['value'] : $this->date2ts($attributes['value']); $dtend_ts = is_numeric($attributes['value']) ? $attributes['value'] : $this->date2ts($attributes['value']);
@ -2317,342 +2302,4 @@ class calendar_ical extends calendar_boupdate
'master_event' => $return_master ? $master_event : false, 'master_event' => $return_master ? $master_event : false,
); );
} }
/**
* generate and insert a VTIMEZONE entry to a vcalendar
*
* @param array $event
* @param array $vcal VCALENDAR entry
* @return string local timezone name (e.g. 'CET/CEST')
*/
function generate_vtimezone($event, &$vcal)
{
$dayofweek = array('SU','MO','TU','WE','TH','FR','SA');
$tbl_tz = array(
array("Afghanistan","Asia/Kabul",270,0,"",0,0,0,0,0,0,0,0,0,0),
array("AKST/AKDT","America/Anchorage",-540,60,"",3,0,2,2,0,11,0,1,2,0),
array("AKST/AKDT","America/Anchorage",-540,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("AKST/AKDT","America/Anchorage",-540,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("HNY/NAY","America/Anchorage",-540,60,"",3,0,2,2,0,11,0,1,2,0),
array("HNY/NAY","America/Anchorage",-540,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("HNY/NAY","America/Anchorage",-540,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Alaskan","America/Anchorage",-540,60,"",3,0,2,2,0,11,0,1,2,0),
array("Alaskan","America/Anchorage",-540,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("Alaskan","America/Anchorage",-540,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Arab","Asia/Riyadh",180,0,"",0,0,0,0,0,0,0,0,0,0),
array("Arabian","Asia/Dubai",240,0,"",0,0,0,0,0,0,0,0,0,0),
array("Arabic","Asia/Baghdad",180,60,"",4,0,1,3,0,10,0,1,4,0),
array("AST/ADT","America/Halifax",-240,60,"",3,0,2,2,0,11,0,1,2,0),
array("AST/ADT","America/Halifax",-240,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("AST/ADT","America/Halifax",-240,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("HNA/HAA","America/Halifax",-240,60,"",3,0,2,2,0,11,0,1,2,0),
array("HNA/HAA","America/Halifax",-240,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("HNA/HAA","America/Halifax",-240,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Atlantic","America/Halifax",-240,60,"",3,0,2,2,0,11,0,1,2,0),
array("Atlantic","America/Halifax",-240,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("Atlantic","America/Halifax",-240,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("AUS_Central","Australia/Darwin",570,0,"",0,0,0,0,0,0,0,0,0,0),
array("AUS_Eastern","Australia/Sydney",600,60,"",10,0,5,2,0,3,0,5,3,0),
array("Azerbaijan","Asia/Baku",240,60,"",3,0,5,4,0,10,0,5,5,0),
array("Azores","Atlantic/Azores",-60,60,"",3,0,5,2,0,10,0,5,3,0),
array("Canada_Central","America/Regina",-360,0,"",0,0,0,0,0,0,0,0,0,0),
array("Cape_Verde","Atlantic/Cape_Verde",-60,0,"",0,0,0,0,0,0,0,0,0,0),
array("Caucasus","Asia/Tbilisi",240,60,"",3,0,5,2,0,10,0,5,3,0),
array("ACST/ACDT","Australia/Adelaide",570,60,"",10,0,5,2,0,3,0,5,3,0),
array("Central_Australia","Australia/Adelaide",570,60,"",10,0,5,2,0,3,0,5,3,0),
array("Central_America","America/Guatemala",-360,0,"",0,0,0,0,0,0,0,0,0,0),
array("Central_Asia","Asia/Dhaka",360,0,"",0,0,0,0,0,0,0,0,0,0),
array("Central_Brazilian","America/Manaus",-240,60,"",11,0,1,0,0,2,0,5,0,0),
array("Central_Brazilian","America/Manaus",-240,60,"2006",11,0,1,0,0,2,0,2,2,0),
array("Central_Brazilian","America/Manaus",-240,60,"2007",11,0,1,0,0,2,0,5,0,0),
array("CET/CEST","Europe/Zurich",60,60,"",3,0,5,2,0,10,0,5,3,0),
array("CET/CEST","Europe/Vienna",60,60,"",3,0,5,2,0,10,0,5,3,0),
array("MEZ/MESZ","Europe/Berlin",60,60,"",3,0,5,2,0,10,0,5,3,0),
array("Central_Europe","Europe/Budapest",60,60,"",3,0,5,2,0,10,0,5,3,0),
array("Central_European","Europe/Warsaw",60,60,"",3,0,5,2,0,10,0,5,3,0),
array("Central_Pacific","Pacific/Guadalcanal",660,0,"",0,0,0,0,0,0,0,0,0,0),
array("CST/CDT","America/Chicago",-360,60,"",3,0,2,2,0,11,0,1,2,0),
array("CST/CDT","America/Chicago",-360,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("CST/CDT","America/Chicago",-360,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("HNC/HAC","America/Chicago",-360,60,"",3,0,2,2,0,11,0,1,2,0),
array("HNC/HAC","America/Chicago",-360,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("HNC/HAC","America/Chicago",-360,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Central","America/Chicago",-360,60,"",3,0,2,2,0,11,0,1,2,0),
array("Central","America/Chicago",-360,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("Central","America/Chicago",-360,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Central_Mexico","America/Mexico_City",-360,60,"",4,0,1,2,0,10,0,5,2,0),
array("China","Asia/Shanghai",480,0,"",0,0,0,0,0,0,0,0,0,0),
array("Dateline","Etc/GMT+12",-720,0,"",0,0,0,0,0,0,0,0,0,0),
array("East_Africa","Africa/Nairobi",180,0,"",0,0,0,0,0,0,0,0,0,0),
array("AEST/AEDT","Australia/Brisbane",600,0,"",0,0,0,0,0,0,0,0,0,0),
array("East_Australia","Australia/Brisbane",600,0,"",0,0,0,0,0,0,0,0,0,0),
array("EET/EEST","Europe/Minsk",120,60,"",3,0,5,2,0,10,0,5,3,0),
array("EET/EEST","Europe/Helsinki",120,60,"",3,0,5,2,0,10,0,5,3,0),
array("East_Europe","Europe/Minsk",120,60,"",3,0,5,2,0,10,0,5,3,0),
array("East_South_America","America/Sao_Paulo",-180,60,"",11,0,1,0,0,2,0,5,0,0),
array("East_South_America","America/Sao_Paulo",-180,60,"2006",11,0,1,0,0,2,0,2,2,0),
array("East_South_America","America/Sao_Paulo",-180,60,"2007",11,0,1,0,0,2,0,5,0,0),
array("EST/EDT","America/New_York",-300,60,"",3,0,2,2,0,11,0,1,2,0),
array("EST/EDT","America/New_York",-300,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("EST/EDT","America/New_York",-300,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("HNE/HAE","America/New_York",-300,60,"",3,0,2,2,0,11,0,1,2,0),
array("HNE/HAE","America/New_York",-300,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("HNE/HAE","America/New_York",-300,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Eastern","America/New_York",-300,60,"",3,0,2,2,0,11,0,1,2,0),
array("Eastern","America/New_York",-300,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("Eastern","America/New_York",-300,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Egypt","Africa/Cairo",120,60,"",4,4,5,23,59,9,4,5,23,59),
array("Ekaterinburg","Asia/Yekaterinburg",300,60,"",3,0,5,2,0,10,0,5,3,0),
array("Fiji","Pacific/Fiji",720,0,"",0,0,0,0,0,0,0,0,0,0),
array("FLE","Europe/Kiev",120,60,"",3,0,5,3,0,10,0,5,4,0),
array("Georgian","Etc/GMT-3",180,0,"",0,0,0,0,0,0,0,0,0,0),
array("GMT","Europe/London",0,60,"",3,0,5,1,0,10,0,5,2,0),
array("Greenland","America/Godthab",-180,60,"",4,0,1,2,0,10,0,5,2,0),
array("Greenwich","Africa/Casablanca",0,0,"",0,0,0,0,0,0,0,0,0,0),
array("GTB","Europe/Istanbul",120,60,"",3,0,5,3,0,10,0,5,4,0),
array("HAST/HADT","Pacific/Honolulu",-600,0,"",0,0,0,0,0,0,0,0,0,0),
array("Hawaiian","Pacific/Honolulu",-600,0,"",0,0,0,0,0,0,0,0,0,0),
array("India","Asia/Calcutta",330,0,"",0,0,0,0,0,0,0,0,0,0),
array("Iran","Asia/Tehran",210,0,"",0,0,0,0,0,0,0,0,0,0),
array("Iran","Asia/Tehran",210,60,"2005",3,0,1,2,0,9,2,4,2,0),
array("Iran","Asia/Tehran",210,0,"2006",0,0,0,0,0,0,0,0,0,0),
array("Israel","Asia/Jerusalem",120,60,"",3,5,5,2,0,9,0,3,2,0),
array("Israel","Asia/Jerusalem",120,0,"2004",0,0,0,0,0,0,0,0,0,0),
array("Israel","Asia/Jerusalem",120,60,"2005",4,-1,1,2,0,10,-1,9,2,0),
array("Israel","Asia/Jerusalem",120,60,"2006",3,-1,31,2,0,10,-1,1,2,0),
array("Israel","Asia/Jerusalem",120,60,"2007",3,-1,30,2,0,9,-1,16,2,0),
array("Israel","Asia/Jerusalem",120,60,"2008",3,-1,28,2,0,10,-1,5,2,0),
array("Israel","Asia/Jerusalem",120,60,"2009",3,-1,27,2,0,9,-1,27,2,0),
array("Israel","Asia/Jerusalem",120,60,"2010",3,-1,26,2,0,9,-1,12,2,0),
array("Israel","Asia/Jerusalem",120,60,"2011",4,-1,1,2,0,10,-1,2,2,0),
array("Israel","Asia/Jerusalem",120,60,"2012",3,-1,30,2,0,9,-1,23,2,0),
array("Israel","Asia/Jerusalem",120,60,"2013",3,-1,29,2,0,9,-1,8,2,0),
array("Israel","Asia/Jerusalem",120,60,"2014",3,-1,28,2,0,9,-1,28,2,0),
array("Israel","Asia/Jerusalem",120,60,"2015",3,-1,27,2,0,9,-1,20,2,0),
array("Israel","Asia/Jerusalem",120,60,"2016",4,-1,1,2,0,10,-1,9,2,0),
array("Israel","Asia/Jerusalem",120,60,"2017",3,-1,31,2,0,9,-1,24,2,0),
array("Israel","Asia/Jerusalem",120,60,"2018",3,-1,30,2,0,9,-1,16,2,0),
array("Israel","Asia/Jerusalem",120,60,"2019",3,-1,29,2,0,10,-1,6,2,0),
array("Israel","Asia/Jerusalem",120,60,"2020",3,-1,27,2,0,9,-1,27,2,0),
array("Israel","Asia/Jerusalem",120,60,"2021",3,-1,26,2,0,9,-1,12,2,0),
array("Israel","Asia/Jerusalem",120,60,"2022",4,-1,1,2,0,10,-1,2,2,0),
array("Israel","Asia/Jerusalem",120,0,"2023",0,0,0,0,0,0,0,0,0,0),
array("Jordan","Asia/Amman",120,60,"",3,4,5,0,0,9,5,5,1,0),
array("Korea","Asia/Seoul",540,0,"",0,0,0,0,0,0,0,0,0,0),
array("Mexico","America/Mexico_City",-360,60,"",4,0,1,2,0,10,0,5,2,0),
array("Mexico_2","America/Chihuahua",-420,60,"",4,0,1,2,0,10,0,5,2,0),
array("Mid_Atlantic","Atlantic/South_Georgia",-120,60,"",3,0,5,2,0,9,0,5,2,0),
array("Middle_East","Asia/Beirut",120,60,"",3,0,5,0,0,10,6,5,23,59),
array("Montevideo","America/Montevideo",-180,60,"",10,0,1,2,0,3,0,2,2,0),
array("MST/MDT","America/Denver",-420,60,"",3,0,2,2,0,11,0,1,2,0),
array("MST/MDT","America/Denver",-420,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("MST/MDT","America/Denver",-420,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("HNR/HAR","America/Denver",-420,60,"",3,0,2,2,0,11,0,1,2,0),
array("HNR/HAR","America/Denver",-420,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("HNR/HAR","America/Denver",-420,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Mountain","America/Denver",-420,60,"",3,0,2,2,0,11,0,1,2,0),
array("Mountain","America/Denver",-420,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("Mountain","America/Denver",-420,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Mountain_Mexico","America/Chihuahua",-420,60,"",4,0,1,2,0,10,0,5,2,0),
array("Myanmar","Asia/Rangoon",390,0,"",0,0,0,0,0,0,0,0,0,0),
array("North_Central_Asia","Asia/Novosibirsk",360,60,"",3,0,5,2,0,10,0,5,3,0),
array("Namibia","Africa/Windhoek",120,-60,"",4,0,1,2,0,9,0,1,2,0),
array("Nepal","Asia/Katmandu",345,0,"",0,0,0,0,0,0,0,0,0,0),
array("New_Zealand","Pacific/Auckland",720,60,"",10,0,1,2,0,3,0,3,3,0),
array("NST/NDT","America/St_Johns",-210,60,"",3,0,2,0,1,11,0,1,0,1),
array("NST/NDT","America/St_Johns",-210,60,"2006",4,0,1,0,1,10,0,5,0,0),
array("NST/NDT","America/St_Johns",-210,60,"2007",3,0,2,0,1,11,0,1,0,0),
array("HNT/HAT","America/St_Johns",-210,60,"",3,0,2,0,1,11,0,1,0,1),
array("HNT/HAT","America/St_Johns",-210,60,"2006",4,0,1,0,1,10,0,5,0,0),
array("HNT/HAT","America/St_Johns",-210,60,"2007",3,0,2,0,1,11,0,1,0,0),
array("Newfoundland","America/St_Johns",-210,60,"",3,0,2,0,1,11,0,1,0,1),
array("Newfoundland","America/St_Johns",-210,60,"2006",4,0,1,0,1,10,0,5,0,0),
array("Newfoundland","America/St_Johns",-210,60,"2007",3,0,2,0,1,11,0,1,0,0),
array("North_Asia_East","Asia/Irkutsk",480,60,"",3,0,5,2,0,10,0,5,3,0),
array("North_Asia","Asia/Krasnoyarsk",420,60,"",3,0,5,2,0,10,0,5,3,0),
array("Pacific_SA","America/Santiago",-240,60,"",10,6,2,23,59,3,6,2,23,59),
array("PST/PDT","America/Los_Angeles",-480,60,"",3,0,2,2,0,11,0,1,2,0),
array("PST/PDT","America/Los_Angeles",-480,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("PST/PDT","America/Los_Angeles",-480,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("HNP/HAP","America/Los_Angeles",-480,60,"",3,0,2,2,0,11,0,1,2,0),
array("HNP/HAP","America/Los_Angeles",-480,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("HNP/HAP","America/Los_Angeles",-480,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Pacific","America/Los_Angeles",-480,60,"",3,0,2,2,0,11,0,1,2,0),
array("Pacific","America/Los_Angeles",-480,60,"2006",4,0,1,2,0,10,0,5,2,0),
array("Pacific","America/Los_Angeles",-480,60,"2007",3,0,2,2,0,11,0,1,2,0),
array("Pacific_Mexico","America/Tijuana",-480,60,"",4,0,1,2,0,10,0,5,2,0),
array("Romance","Europe/Paris",60,60,"",3,0,5,2,0,10,0,5,3,0),
array("Russian","Europe/Moscow",180,60,"",3,0,5,2,0,10,0,5,3,0),
array("SA_Eastern","Etc/GMT+3",-180,0,"",0,0,0,0,0,0,0,0,0,0),
array("SA_Pacific","America/Bogota",-300,0,"",0,0,0,0,0,0,0,0,0,0),
array("SA_Western","America/La_Paz",-240,0,"",0,0,0,0,0,0,0,0,0,0),
array("Samoa","Pacific/Apia",-660,0,"",0,0,0,0,0,0,0,0,0,0),
array("SE_Asia","Asia/Bangkok",420,0,"",0,0,0,0,0,0,0,0,0,0),
array("Singapore","Asia/Singapore",480,0,"",0,0,0,0,0,0,0,0,0,0),
array("South_Africa","Africa/Johannesburg",120,0,"",0,0,0,0,0,0,0,0,0,0),
array("Sri_Lanka","Asia/Colombo",330,0,"",0,0,0,0,0,0,0,0,0,0),
array("Taipei","Asia/Taipei",480,0,"",0,0,0,0,0,0,0,0,0,0),
array("Tasmania","Australia/Hobart",600,60,"",10,0,1,2,0,3,0,5,3,0),
array("Tokyo","Asia/Tokyo",540,0,"",0,0,0,0,0,0,0,0,0,0),
array("Tonga","Pacific/Tongatapu",780,0,"",0,0,0,0,0,0,0,0,0,0),
array("US_Eastern","Etc/GMT+5",-300,0,"",0,0,0,0,0,0,0,0,0,0),
array("US_Mountain","America/Phoenix",-420,0,"",0,0,0,0,0,0,0,0,0,0),
array("Vladivostok","Asia/Vladivostok",600,60,"",3,0,5,2,0,10,0,5,3,0),
array("West_Australia","Australia/Perth",480,60,"",10,0,5,2,0,3,0,5,3,0),
array("West_Australia","Australia/Perth",480,0,"2005",0,0,0,0,0,0,0,0,0,0),
array("West_Australia","Australia/Perth",480,60,"2006",12,-1,1,2,0,1,-1,1,0,0),
array("West_Australia","Australia/Perth",480,60,"2007",10,0,5,2,0,3,0,5,3,0),
array("West_Central_Africa","Africa/Lagos",60,0,"",0,0,0,0,0,0,0,0,0,0),
array("WET/WEST","Europe/Berlin",60,60,"",3,0,5,2,0,10,0,5,3,0),
array("West_Europe","Europe/Berlin",60,60,"",3,0,5,2,0,10,0,5,3,0),
array("West_Asia","Asia/Karachi",300,0,"",0,0,0,0,0,0,0,0,0,0),
array("West_Pacific","Pacific/Port_Moresby",600,0,"",0,0,0,0,0,0,0,0,0,0),
array("Yakutsk","Asia/Yakutsk",540,60,"",3,0,5,2,0,10,0,5,3,0),
);
$serverTZ = date('e', $event['start']);
$year = date('Y', $event['start']);
$i = 0;
$row = false;
do
{
$tbl_tz_row =& $tbl_tz[$i];
if ($tbl_tz_row[1] == $serverTZ)
{
if ($tbl_tz_row[4] == '' || $year >= (int) $tbl_tz_row[4])
{
$row = $i;
}
elseif ($row !== false) break;
elseif ($tbl_tz_row[4] != '' && $year < (int) $tbl_tz_row[4])
{
// First DST starts at this year
$year = (int) $tbl_tz_row[4];
if (empty($event['recur_enddate'])
|| $year <= date('Y', $event['recur_enddate']))
{
$row = $i;
}
break;
}
}
elseif ($row !== false) break;
}
while (is_array($tbl_tz[++$i]));
if ($row === false) return $serverTZ; // UTC or unkown TZ
$tbl_tz_row =& $tbl_tz[$row];
if (preg_match('/(.+)\/(.+)/', $tbl_tz_row[0], $matches))
{
$stdname = $matches[1];
$dstname = $matches[2];
}
else
{
$stdname = $dstname = $tbl_tz_row[0];
}
$container = false;
$vtimezone = Horde_iCalendar::newComponent('VTIMEZONE', $container);
$vtimezone->setAttribute('TZID', $tbl_tz_row[1]);
do {
if (is_array($tbl_tz[++$row]))
{
$tbl_next_row =& $tbl_tz[$row];
if ($tbl_next_row[1] != $serverTZ) $tbl_next_row = false;
}
else $tbl_next_row = false;
$minutes = $tbl_tz_row[2] + $tbl_tz_row[3];
$value1['ahead'] = ($minutes >= 0);
$minutes = abs($minutes);
$value1['hour'] = (int)$minutes / 60;
$value1['minute'] = $minutes % 60;
$minutes = $tbl_tz_row[2];
$value2['ahead'] = ($minutes > 0);
$minutes = abs($minutes);
$value2['hour'] = (int)$minutes / 60;
$value2['minute'] = $minutes % 60;
$daylight = Horde_iCalendar::newComponent('DAYLIGHT', $container);
$dtstart = $this->calc_dtstart($year, $tbl_tz_row[5],
$tbl_tz_row[6], $tbl_tz_row[7], $tbl_tz_row[8], $tbl_tz_row[9]);
$daylight->setAttribute('DTSTART', $dtstart);
$byday = ($tbl_tz_row[7] == 5 ? '-1' : $tbl_tz_row[7]) . $dayofweek[$tbl_tz_row[6]];
$rrule = array('FREQ' => 'YEARLY', 'BYMONTH' => $tbl_tz_row[5], 'BYDAY' => $byday);
if ($tbl_next_row)
{
$rrule['UNTIL'] = $tbl_next_row[4] . '0101T000000Z';
}
$daylight->setAttribute('RRULE', '', $rrule);
$daylight->setAttribute('TZNAME', $dstname);
$daylight->setAttribute('TZOFFSETFROM', $value2);
$daylight->setAttribute('TZOFFSETTO', $value1);
$standard = Horde_iCalendar::newComponent('STANDARD', $container);
$dtstart = $this->calc_dtstart($year, $tbl_tz_row[10], $tbl_tz_row[11],
$tbl_tz_row[12], $tbl_tz_row[13], $tbl_tz_row[14]);
$standard->setAttribute('DTSTART', $dtstart);
$byday = ($tbl_tz_row[12] == 5 ? '-1' : $tbl_tz_row[12]) . $dayofweek[$tbl_tz_row[11]];
$rrule['BYMONTH'] = $tbl_tz_row[10];
$rrule['BYDAY'] = $byday;
$standard->setAttribute('RRULE', '', $rrule);
$standard->setAttribute('TZNAME', $stdname);
$standard->setAttribute('TZOFFSETFROM', $value1);
$standard->setAttribute('TZOFFSETTO', $value2);
$vtimezone->addComponent($daylight);
$vtimezone->addComponent($standard);
if ($tbl_next_row)
{
$tbl_tz_row = $tbl_next_row;
$year = (int) $tbl_tz_row[4];
}
} while ($tbl_next_row && (empty($event['recur_enddate']) ||
$year <= date('Y', $event['recur_enddate'])));
$vcal->addComponent($vtimezone);
return $serverTZ;
}
/**
* calculate the DTSTART value for a given timezone switch occurrence
*
* @param int $wYear
* @param int $wMonth
* @param int $wDayOfWeek
* @param int $wNth n-th day of week (5 last occurrence)
* @param int $wHour
* @param int $wMinute
* @return string DTSTART entry
*/
function calc_dtstart($wYear, $wMonth, $wDayOfWeek, $wNth, $wHour, $wMinute)
{
if (!$wYear) $wYear = 1981;
if ($wNth < 5)
{
$ts = mktime($wHour, $wMinute, 0, $wMonth, 1, $wYear);
$day = $wDayOfWeek - date('w', $ts);
if ($day < 0) $day += 7;
$day += 7 * ($wNth - 1) + 1;
$ts = mktime($wHour, $wMinute, 0, $wMonth, $day, $wYear);
}
else
{
$ts = mktime($wHour, $wMinute, 0, $wMonth, 31, $wYear);
$day = $wDayOfWeek - date('w', $ts);
if ($day > 0) $day -= 7;
$day += 31;
do
{
$ts = mktime($wHour, $wMinute, 0, $wMonth, $day, $wYear);
$day -= 7;
} while ($wMonth < date('n', $ts));
}
$dtstart = date('Ymd\T', $ts) . sprintf("%'02u%'02u00", $wHour, $wMinute);
return $dtstart;
}
} }