Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iCalDateWithTimeZone calculation always starts at UTC #197

Closed
tyzoid opened this issue Dec 30, 2018 · 1 comment
Closed

iCalDateWithTimeZone calculation always starts at UTC #197

tyzoid opened this issue Dec 30, 2018 · 1 comment
Labels

Comments

@tyzoid
Copy link

tyzoid commented Dec 30, 2018

  • PHP Version: 7.2.10
  • PHP date.timezone: N/A
  • ICS Parser Version: 2.1.7
  • Ubuntu Server 18.04

Description of the Issue:

When setting the calendar timezone, conversions from the event time to the calendar time occur from UTC, completely ignoring the calendar default timezone. This not only yields a counterintuitive result, but also an incorrect one.

For example, a DTSTART of TZID=America/New_York:20181204T180000 will get converted to a dtstart_tz of 20181204T130000 when the calendar default is set to Europe/Copenhagen. Instead of being converted to UTC or Europe/Copenhagen (+5 or +6hrs after America/New_York at time of writing), the dtstart_tz gets converted to something that's -5 hours from America/New_York.

It should be added, that the unix timestamp parsed as element 2 of dtstart_array is correct.

Steps to Reproduce:

Example iCalendar (https://dl.tyzoid.com/test.ics):

BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:America/New_York
TZURL:http://tzurl.org/zoneinfo/America/New_York
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20181213T205417
DTSTAMP:20181213T205417
LAST-MODIFIED:20181213T205417
UID:49ZKIH630HTZV3YK8NJZY
SUMMARY:CSGO
CLASS:PUBLIC
STATUS:CONFIRMED
RRULE:FREQ=WEEKLY
DESCRIPTION:Hosted by Avery
DTSTART;TZID=America/New_York:20181204T180000
DTEND;TZID=America/New_York:20181204T190000
END:VEVENT
END:VCALENDAR

Example Code:

<?php
date_default_timezone_set('Europe/Copenhagen');

$ical = new ICal(
    "https://dl.tyzoid.com/test.ics",
    ['defaultTimeZone' => 'Europe/Copenhagen']
);

var_dump($ical->events()[0]);

This yields the following (snippet)

  ["dtstart_array"]=>
  array(4) {
    [0]=>
    array(1) {
      ["TZID"]=>
      string(16) "America/New_York"
    }
    [1]=>
    string(15) "20181204T180000"
    [2]=>
    int(1543964400)
    [3]=>
    string(37) "TZID=America/New_York:20181204T180000"
  }
  ["dtend_array"]=>
  array(4) {
    [0]=>
    array(1) {
      ["TZID"]=>
      string(16) "America/New_York"
    }
    [1]=>
    string(15) "20181204T190000"
    [2]=>
    int(1543968000)
    [3]=>
    string(37) "TZID=America/New_York:20181204T190000"
  }
  ["dtstart_tz"]=>
  string(15) "20181204T130000"
  ["dtend_tz"]=>
  string(15) "20181204T140000"

Code Exploration

It seems like this is down to the following code, inside iCalDateWithTimeZone:

        if ($key === 'DURATION') {
            $duration = end($dateArray);
            $dateTime = $this->parseDuration($event['DTSTART'], $duration, null);
        } else {
            $dateTime = new \DateTime($dateArray[1], new \DateTimeZone(self::TIME_ZONE_UTC));
            $dateTime->setTimezone(new \DateTimeZone($this->calendarTimeZone()));
        }
        // Force time zone
        if (isset($dateArray[0]['TZID'])) {
            if ($this->isValidIanaTimeZoneId($dateArray[0]['TZID'])) {
                $dateTime->setTimezone(new \DateTimeZone($dateArray[0]['TZID']));
            } elseif ($this->isValidCldrTimeZoneId($dateArray[0]['TZID'])) {
                $dateTime->setTimezone(new \DateTimeZone($this->isValidCldrTimeZoneId($dateArray[0]['TZID'], true)));
            } else {
                $dateTime->setTimezone(new \DateTimeZone($this->defaultTimeZone));
            }
        }

This parses the value of $dateArray[1], which in this case, is 20181204T190000 for DTSTART, as UTC. It then sets the timezone with the calendar time zone, and finally with the "forced" timezone information found in $dateArray[0], which in this case is America/New_York.

The error, as far as I can tell, is that instead of parsing the time as America/New_York to start, it parses as UTC, then tries to set it to the event timezone of America/New_York.

I'm not familiar enough with this library to know if changing the behaviour in this function will produce side effects, so I've simply documented my findings here.

@u01jmg3 u01jmg3 self-assigned this Dec 30, 2018
@u01jmg3
Copy link
Owner

u01jmg3 commented Jan 2, 2019

Many thanks for the thorough description. Shall check this out in due course but time zone issues are always tricky to solve.

@u01jmg3 u01jmg3 closed this as completed Jul 17, 2019
@u01jmg3 u01jmg3 removed their assignment Jul 17, 2019
@u01jmg3 u01jmg3 added this to the v2.x.x milestone Jul 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants