Adds TZID/VTIMEZONE support for server timezone entries

This commit is contained in:
Jörg Lehrke 2009-10-05 21:00:08 +00:00
parent b5673ab38a
commit 1353ae511a

View File

@ -192,14 +192,6 @@ class calendar_ical extends calendar_boupdate
$version = '2.0';
}
$servertime = false;
$date_format = 'server';
if (strpos($this->productName, "palmos") )
{
$servertime = true;
$date_format = 'ts';
}
$vcal = new Horde_iCalendar;
$vcal->setAttribute('PRODID','-//eGroupWare//NONSGML eGroupWare Calendar '.$GLOBALS['egw_info']['apps']['calendar']['version'].'//'.
strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang']));
@ -210,10 +202,18 @@ class calendar_ical extends calendar_boupdate
while (($event = array_pop($events)))
{
if (strpos($this->productName, 'palmos'))
{
$servertime = true;
$date_format = 'ts';
}
else
{
$servertime = false;
}
if (!is_array($event)
&& !($event = $this->read($event, $recur_date, false, $date_format)))
{
// server = timestamp in server-time(!)
return false; // no permission to read $cal_id
}
if ($recur_date)
@ -225,17 +225,25 @@ class calendar_ical extends calendar_boupdate
}
$event['recur_type'] = MCAL_RECUR_NONE;
}
//_debug_array($event);
// correct daylight saving time
/* causes times wrong by one hour, if exporting events with DST different from the current date,
which this fix is suppost to fix. Maybe the problem has been fixed in the horde code too.
$currentDST = date('I', mktime());
$eventDST = date('I', $event['start']);
$DSTCorrection = ($currentDST - $eventDST) * 3600;
$event['start'] = $event['start'] + $DSTCorrection;
$event['end'] = $event['end'] + $DSTCorrection;
*/
if ($this->log) error_log(__FILE__.'('.__LINE__.'): '.__METHOD__.' '.array2string($event)."\n",3,$this->logfile);
if (!$servertime && $event['recur_type'] != MCAL_RECUR_NONE)
{
if ($event['recur_enddate'])
{
$startDST = date('I', $event['start']);
$finalDST = date('I', $event['recur_enddate']);
// Different DST or more than half a year?
if ($startDST != $finalDST ||
($event['recur_enddate'] - $event['start']) > 15778800)
{
$servertime = true;
// read the event again with timestamps
$event = $this->read($event['id'], 0, false, 'ts');
}
}
}
if ($this->productManufacturer != 'file' && $this->uidExtension)
{
@ -248,6 +256,15 @@ class calendar_ical extends calendar_boupdate
$vevent = Horde_iCalendar::newComponent('VEVENT', $vcal);
$parameters = $attributes = $values = array();
if ($servertime)
{
$serverTZ = $this->generate_vtimezone($event['start'], $vevent);
}
else
{
$serverTZ = null;
}
if ($this->productManufacturer == 'sonyericsson')
{
$eventDST = date('I', $event['start']);
@ -324,6 +341,7 @@ class calendar_ical extends calendar_boupdate
if ($servertime)
{
$attributes['DTSTART'] = date('Ymd\THis', $event['start']);
if ($serverTZ) $parameters['DTSTART']['TZID'] = $serverTZ;
}
else
{
@ -349,6 +367,7 @@ class calendar_ical extends calendar_boupdate
if ($servertime)
{
$attributes['DTEND'] = date('Ymd\THis', $event['end']);
if ($serverTZ) $parameters['DTEND']['TZID'] = $serverTZ;
}
else
{
@ -388,14 +407,7 @@ class calendar_ical extends calendar_boupdate
{
$recur_enddate = (int)$event['recur_enddate'];
$recur_enddate += 24 * 60 * 60 - 1;
if ($servertime)
{
$rrule['UNTIL'] = date('Ymd\THis', $recur_enddate);
}
else
{
$rrule['UNTIL'] = $vcal->_exportDateTime($recur_enddate);
}
$rrule['UNTIL'] = $vcal->_exportDateTime($recur_enddate);
}
else
{
@ -440,14 +452,7 @@ class calendar_ical extends calendar_boupdate
}
else
{
if ($servertime)
{
$rrule['UNTIL'] = date('Ymd\THis', $recur_enddate);
}
else
{
$rrule['UNTIL'] = $vcal->_exportDateTime($recur_enddate);
}
$rrule['UNTIL'] = $vcal->_exportDateTime($recur_enddate);
}
}
// no idea how to get the Horde parser to produce a standard conformant
@ -528,6 +533,7 @@ class calendar_ical extends calendar_boupdate
}
$attributes['EXDATE'] = '';
$values['EXDATE'] = $days;
if ($serverTZ) $parameters['EXDATE']['TZID'] = $serverTZ;
$parameters['EXDATE']['VALUE'] = $value_type;
}
break;
@ -571,6 +577,7 @@ class calendar_ical extends calendar_boupdate
if ($servertime)
{
$attributes['RECURRENCE-ID'] = date('Ymd\THis', $recur_date);
if ($serverTZ) $parameters['RECURRENCE-ID']['TZID'] = $serverTZ;
}
else
{
@ -598,6 +605,7 @@ class calendar_ical extends calendar_boupdate
if ($servertime)
{
$attributes['RECURRENCE-ID'] = date('Ymd\THis', $event['recurrence']);
if ($serverTZ) $parameters['RECURRENCE-ID']['TZID'] = $serverTZ;
}
else
{
@ -655,35 +663,14 @@ class calendar_ical extends calendar_boupdate
if (!$created && !$modified) $created = $event['modified'];
if ($created)
{
if ($servertime)
{
$attributes['CREATED'] = date('Ymd\THis', $created);
}
else
{
$attributes['CREATED'] = $created;
}
$attributes['CREATED'] = $created;
}
if (!$modified) $modified = $event['modified'];
if ($modified)
{
if ($servertime)
{
$attributes['LAST-MODIFIED'] = date('Ymd\THis', $modified);
}
else
{
$attributes['LAST-MODIFIED'] = $modified;
}
}
if ($servertime)
{
$attributes['DTSTAMP'] = date('Ymd\THis', time());
}
else
{
$attributes['DTSTAMP'] = time();
$attributes['LAST-MODIFIED'] = $modified;
}
$attributes['DTSTAMP'] = time();
foreach($event['alarm'] as $alarmID => $alarmData)
{
// skip alarms being set for all users or alarms owned by other users
@ -691,13 +678,15 @@ class calendar_ical extends calendar_boupdate
{
continue;
}
if ($version == '1.0')
{
if ($servertime)
{
$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;
}
else
{
@ -719,6 +708,12 @@ class calendar_ical extends calendar_boupdate
// RFC requires DESCRIPTION for DISPLAY
if (!$event['title'] && !$description) continue;
if ($this->isWholeDay($event) && $alarmData['offset'])
{
$alarmData['time'] = $event['start'] - $alarmData['offset'];
$alarmData['offset'] = false;
}
$valarm = Horde_iCalendar::newComponent('VALARM',$vevent);
if ($alarmData['offset'])
{
@ -727,15 +722,17 @@ class calendar_ical extends calendar_boupdate
}
else
{
$params = array('VALUE' => 'DATE-TIME');
if ($servertime)
{
$value = date('Ymd\THis', $alarmData['time']);
if ($serverTZ) $params['TZID'] = $serverTZ;
}
else
{
$value = $alarmData['time'];
}
$valarm->setAttribute('TRIGGER', $value, array('VALUE' => 'DATE-TIME'));
$valarm->setAttribute('TRIGGER', $value, $params);
}
$valarm->setAttribute('ACTION','DISPLAY');
@ -824,7 +821,7 @@ class calendar_ical extends calendar_boupdate
{
$event['owner'] = $GLOBALS['egw_info']['user']['account_id'];
}
// add ourself to new events as participant
if(!isset($this->supportedFields['participants'])
||!isset($event['participants'][$GLOBALS['egw_info']['user']['account_id']]))
@ -896,7 +893,7 @@ class calendar_ical extends calendar_boupdate
{
case 'SINGLE':
Horde::logMessage('importVCAL event SINGLE',__FILE__, __LINE__, PEAR_LOG_DEBUG);
// update the event
if($event_info['acl_edit'])
{
@ -905,10 +902,10 @@ class calendar_ical extends calendar_boupdate
unset($event_to_store);
}
break;
case 'SERIES-MASTER':
Horde::logMessage('importVCAL event SERIES-MASTER',__FILE__, __LINE__, PEAR_LOG_DEBUG);
// remove all known "status only" exceptions and update the event
if($event_info['acl_edit'])
{
@ -925,17 +922,17 @@ class calendar_ical extends calendar_boupdate
}
$event['recur_exception'] = $recur_exceptions;
}
$event_to_store = $event; // prevent $event from being changed by the update method
$updated_id = $this->update($event_to_store, true);
unset($event_to_store);
}
break;
case 'SERIES-EXCEPTION':
case 'SERIES-EXCEPTION-PROPAGATE':
Horde::logMessage('importVCAL event SERIES-EXCEPTION',__FILE__, __LINE__, PEAR_LOG_DEBUG);
// update event
if($event_info['acl_edit'])
{
@ -956,16 +953,16 @@ class calendar_ical extends calendar_boupdate
$event['reference'] = $event_info['master_event']['id'];
$event['category'] = $event_info['master_event']['category'];
}
$event_to_store = $event; // prevent $event from being changed by update method
$updated_id = $this->update($event_to_store, true);
unset($event_to_store);
}
break;
case 'SERIES-EXCEPTION-STATUS':
Horde::logMessage('importVCAL event SERIES-EXCEPTION-STATUS',__FILE__, __LINE__, PEAR_LOG_DEBUG);
if($event_info['acl_edit'])
{
// truncate the status only exception from the series master
@ -978,22 +975,22 @@ class calendar_ical extends calendar_boupdate
}
}
$event_info['master_event']['recur_exception'] = $recur_exceptions;
// save the series master with the adjusted exceptions
$event_to_store = $event_info['master_event']; // prevent the master_event from being changed by the update method
$updated_id = $this->update($event_to_store, true);
unset($event_to_store);
}
break;
}
// read stored event into info array for fresh stored (new) events
if(!is_array($event_info['stored_event']) && $updated_id > 0)
{
$event_info['stored_event'] = $this->read($updated_id);
}
// update status depending on the given event type
switch($event_info['type'])
{
@ -1016,7 +1013,7 @@ class calendar_ical extends calendar_boupdate
}
}
break;
case 'SERIES-EXCEPTION-STATUS':
if(is_array($event_info['master_event'])) // status update requires a stored master event
{
@ -1034,9 +1031,9 @@ class calendar_ical extends calendar_boupdate
}
break;
}
// update alarms depending on the given event type
if(isset($this->supportedFields['alarm'])
if(isset($this->supportedFields['alarm'])
&& is_array($event_info['stored_event']) // alarm update requires a stored event
)
{
@ -1078,7 +1075,7 @@ class calendar_ical extends calendar_boupdate
}
}
break;
case 'SERIES-EXCEPTION-STATUS':
// nothing to do here
break;
@ -1093,11 +1090,11 @@ class calendar_ical extends calendar_boupdate
case 'SERIES-EXCEPTION':
$return_id = is_array($event_info['stored_event']) ? $event_info['stored_event']['id'] : false;
break;
case 'SERIES-EXCEPTION-STATUS':
$return_id = is_array($event_info['master_event']) ? $event_info['master_event']['id'] . ':' . $event['recurrence'] : false;
break;
case 'SERIES-EXCEPTION-PROPAGATE':
if($event_info['acl_edit'] && is_array($event_info['stored_event']))
{
@ -1119,7 +1116,7 @@ class calendar_ical extends calendar_boupdate
error_log(__LINE__.__METHOD__.__FILE__.array2string($egw_event)."\n",3,$this->logfile);
}
}
return $return_id;
}
@ -1425,7 +1422,7 @@ class calendar_ical extends calendar_boupdate
// No reference or RECURRENCE-ID for the series master
$event['reference'] = $event['recurrence'] = 0;
}
// handle the alarms
$alarms = $event['alarm'];
foreach ($component->getComponents() as $valarm)
@ -1436,12 +1433,12 @@ class calendar_ical extends calendar_boupdate
}
}
$event['alarm'] = $alarms;
$events[] = $event;
}
}
}
// decide what to return
if(count($events) == 1)
{
@ -1449,7 +1446,7 @@ class calendar_ical extends calendar_boupdate
if($cal_id > 0) $event['id'] = $cal_id;
if(!is_null($etag)) $event['etag'] = $etag;
if($recur_date) $event['recurrence'] = $recur_date;
return array($event);
}
else if($count($events) == 0 || $cal_id > 0 || !is_null($etag) || $recur_date)
@ -2024,7 +2021,7 @@ class calendar_ical extends calendar_boupdate
{
$event = array_shift($events);
return $this->find_event($event, $relax);
}
}
}
return false;
}
@ -2139,16 +2136,16 @@ class calendar_ical extends calendar_boupdate
$this->set_status($old_event, $userid, $status, $recur_date, true);
}
}
/**
* classifies an incoming event from the eGW point-of-view
*
*
* exceptions: unlike other calendar apps eGW does not create an event exception
* if just the participant state changes - therefore we have to distinguish between
* real exceptions and status only exceptions
*
*
* @param array $event the event to check
*
*
* @return array
* type =>
* SINGLE a single event
@ -2165,7 +2162,7 @@ class calendar_ical extends calendar_boupdate
{
$type = 'SINGLE'; // default
$return_master = false; //default
if($event['recur_type'] != MCAL_RECUR_NONE)
{
$type = 'SERIES-MASTER';
@ -2187,7 +2184,7 @@ class calendar_ical extends calendar_boupdate
{
// SERIES-EXCEPTION OR SERIES-EXCEPTON-STATUS
$return_master = true; // we have a valid master and can return it
if(isset($event['id']) && $master_event['id'] != $event['id'])
{
$type = 'SERIES-EXCEPTION'; // this is an existing exception
@ -2218,7 +2215,7 @@ class calendar_ical extends calendar_boupdate
}
// the event id here is always the id of the master event
// unset it to prevent confusion of stored event and master event
unset($event['id']);
unset($event['id']);
}
}
else
@ -2227,13 +2224,13 @@ class calendar_ical extends calendar_boupdate
$type = 'SINGLE';
}
}
// read existing event
if(isset($event['id']))
{
$stored_event = $this->read($event['id']);
}
// check ACL
if($return_master)
{
@ -2250,7 +2247,7 @@ class calendar_ical extends calendar_boupdate
$acl_edit = true; // new event
}
}
return array(
'type' => $type,
'acl_edit' => $acl_edit,
@ -2258,4 +2255,297 @@ class calendar_ical extends calendar_boupdate
'master_event' => $return_master ? $master_event : false,
);
}
/**
* generate and insert a VTIMEZONE entry for an event
*
* @param int $ts timestamp to evaluate the local timezone and year
* @param array $vevent VEVENT representation of the event
* @return string local timezone name (e.g. 'CET/CEST')
*/
function generate_vtimezone($ts, &$vevent)
{
$utc = array('UTC',null,0,0,"",0,0,0,0,0,0,0,0,0,0);
$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("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("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', $ts);
$year = date('Y', $ts);
$i = 0;
$row =& $utc;
do
{
$tbl_tz_row =& $tbl_tz[$i];
if ($row[0] != 'UTC' && $row[0] != $tbl_tz_row[0]) break;
if ($tbl_tz_row[1] == $serverTZ
&& ($tbl_tz_row[4] != "" || $year >= (int) $tbl_tz_row[4]))
{
$row =& $tbl_tz[$i];
}
$i++;
}
while (is_array($tbl_tz[$i]));
if (preg_match('/(.+)\/(.+)/', $row[0], $matches))
{
$stdname = $matches[1];
$dstname = $matches[2];
}
else
{
$stdname = $dstname = $row[0];
}
$container = false;
$vtimezone = Horde_iCalendar::newComponent('VTIMEZONE', $container);
$vtimezone->setAttribute('TZID', $row[1]);
$minutes = $row[2] + $row[3];
$value1['ahead'] = ($minutes > 0);
$minutes = abs($minutes);
$value1['hour'] = (int)$minutes / 60;
$value1['minute'] = $minutes % 60;
$minutes = $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($row[4], $row[5], $row[6], $row[7], $row[8], $row[9]);
$daylight->setAttribute('DTSTART', $dtstart);
$byday = ($row[7] == 5 ? '-1' : $row[7]) . $dayofweek[$row[6]];
$daylight->setAttribute('RRULE', '', array('FREQ' => 'YEARLY', 'BYMONTH' => $row[5], 'BYDAY' => $byday));
$daylight->setAttribute('TZNAME', $dstname);
$daylight->setAttribute('TZOFFSETFROM', $value2);
$daylight->setAttribute('TZOFFSETTO', $value1);
$standard = Horde_iCalendar::newComponent('STANDARD', $container);
$dtstart = $this->calc_dtstart($year, $row[10], $row[11], $row[12], $row[13], $row[14]);
$standard->setAttribute('DTSTART', $dtstart);
$byday = ($row[12] == 5 ? '-1' : $row[12]) . $dayofweek[$row[11]];
$standard->setAttribute('RRULE', '', array('FREQ' => 'YEARLY', 'BYMONTH' => $row[10], 'BYDAY' => $byday));
$standard->setAttribute('TZNAME', $stdname);
$standard->setAttribute('TZOFFSETFROM', $value1);
$standard->setAttribute('TZOFFSETTO', $value2);
$vtimezone->addComponent($daylight);
$vtimezone->addComponent($standard);
$vevent->addComponent($vtimezone);
return $row[1];
}
/**
* 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;
}
}