Creating an iCalender VTIMEZONE Component from a PHP Time Zone Time Value

I am adding a function to the event calendar application to provide iCalendar (ics) files for events. I want to create a VTIMEZONEComponent , but all I have is a PHP Timezone value from date_default_timezone_get(). Here is an example of a component VTIMEZONEfor Eastern Time (USA and Canada) that Outlook created:

BEGIN:VTIMEZONE
TZID:Eastern Time (US & Canada)
BEGIN:STANDARD
DTSTART:16011104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:16010311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
END:VTIMEZONE

This will behave like the PHP timezone "America / New_York", but how can I automate it?

+5
source share
3 answers

PHP DateTimezoneclass works with Olson timezone database and has some (limited) methods , .

RFC 5545, RRULE , VTIMEZONE . RFC, :

use \Sabre\VObject;

/**
 * Returns a VTIMEZONE component for a Olson timezone identifier
 * with daylight transitions covering the given date range.
 *
 * @param string Timezone ID as used in PHP Date functions
 * @param integer Unix timestamp with first date/time in this timezone
 * @param integer Unix timestap with last date/time in this timezone
 *
 * @return mixed A Sabre\VObject\Component object representing a VTIMEZONE definition
 *               or false if no timezone information is available
 */
function generate_vtimezone($tzid, $from = 0, $to = 0)
{
    if (!$from) $from = time();
    if (!$to)   $to = $from;

    try {
        $tz = new \DateTimeZone($tzid);
    }
    catch (\Exception $e) {
        return false;
    }

    // get all transitions for one year back/ahead
    $year = 86400 * 360;
    $transitions = $tz->getTransitions($from - $year, $to + $year);

    $vt = new VObject\Component('VTIMEZONE');
    $vt->TZID = $tz->getName();

    $std = null; $dst = null;
    foreach ($transitions as $i => $trans) {
        $cmp = null;

        // skip the first entry...
        if ($i == 0) {
            // ... but remember the offset for the next TZOFFSETFROM value
            $tzfrom = $trans['offset'] / 3600;
            continue;
        }

        // daylight saving time definition
        if ($trans['isdst']) {
            $t_dst = $trans['ts'];
            $dst = new VObject\Component('DAYLIGHT');
            $cmp = $dst;
        }
        // standard time definition
        else {
            $t_std = $trans['ts'];
            $std = new VObject\Component('STANDARD');
            $cmp = $std;
        }

        if ($cmp) {
            $dt = new DateTime($trans['time']);
            $offset = $trans['offset'] / 3600;

            $cmp->DTSTART = $dt->format('Ymd\THis');
            $cmp->TZOFFSETFROM = sprintf('%s%02d%02d', $tzfrom >= 0 ? '+' : '', floor($tzfrom), ($tzfrom - floor($tzfrom)) * 60);
            $cmp->TZOFFSETTO   = sprintf('%s%02d%02d', $offset >= 0 ? '+' : '', floor($offset), ($offset - floor($offset)) * 60);

            // add abbreviated timezone name if available
            if (!empty($trans['abbr'])) {
                $cmp->TZNAME = $trans['abbr'];
            }

            $tzfrom = $offset;
            $vt->add($cmp);
        }

        // we covered the entire date range
        if ($std && $dst && min($t_std, $t_dst) < $from && max($t_std, $t_dst) > $to) {
            break;
        }
    }

    // add X-MICROSOFT-CDO-TZID if available
    $microsoftExchangeMap = array_flip(VObject\TimeZoneUtil::$microsoftExchangeMap);
    if (array_key_exists($tz->getName(), $microsoftExchangeMap)) {
        $vt->add('X-MICROSOFT-CDO-TZID', $microsoftExchangeMap[$tz->getName()]);
    }

    return $vt;
}

Sabre VObject VTIMEZONE, .

, , unix. .

iTip, Outlook, Olson Microsoft.

+6

, , VTIMEZONE , - (, "/-" / " " ( ) " VEVENT PHP DateTime class.

$Date = new DateTime( $event_date ); // this will be in the server time zone

// convert it to the 'internal' time zone
$Date->setTimezone( new DateTimeZone( 'America/New_York' ) );

// ...

echo "BEGIN:VEVENT\n";
echo "DTSTART;TZID=America/New_York:" . $Date->format( 'Ymd\THis' ) . "\n"

- !

, .

+4

PHP has an internationalization extension called intl , a simple shell for the core library from IBM called ICU - International Components for Unicode , which does all the dirty work.

Now ICU implements com.ibm.icu.util.VTimeZone , capable of generating iCal VTIMEZONE components using daylight saving time (using Olson tz db transitions).

Great !! But .. this class has not earned a wrapper in PHP.

+2
source

All Articles