u01jmg3 / ics-parser

Parser for iCalendar Events • PHP 8+, 7 (≥ 7.4), 5 (≥ 5.6)
MIT License
448 stars 144 forks source link

iCalDateToDateTime possibly overlooking timezone #241

Closed murraycollingwood closed 4 years ago

murraycollingwood commented 4 years ago

Description of the Issue:

The local time loaded from this ICS When extracted using iCalDateToDateTime appears to be correct When getTimestamp is run the time appears to be in UTC (has it ignored the timezone)?

Steps to Reproduce:

I'm loading the ICS

BEGIN:VEVENT
TRANSP:OPAQUE
DTSTART;TZID=Pacific/Auckland:20191015T120000
DTEND;TZID=Pacific/Auckland:20191015T125000
CREATED:20190101T000000Z
UID:E943400B00B5F7-THAZT-05FA
SEQUENCE:737329
SUMMARY:Sample ics
LOCATION:Localhost
DESCRIPTION:Sample
END:VEVENT

I'm trying to get this to a local unix timestamp: I have included the important lines of code and the relative values at each stage:

// event->dtstart_array[3] = TZID=Pacific/Auckland:20191015T120000
$dtstart = $ical->iCalDateToDateTime($event->dtstart_array[3], true);
// iCalDateToDateTime dtstart = 2019-10-15 12:00:00
$timestart = $dtstart->getTimestamp();
// getTimestamp timestart = 1571094000
strftime timestart = 2019-10-15 09:00:00

In the iCalDateToDateTime() I initially had false for the second parameter, I tried changing it to true, but it makes no difference to this result.

Maybe I'm doing something dumb, but I just can't see it.

TIA

I tried uploading the ICS file, but apparently github doesn't support that type of file.

murraycollingwood commented 4 years ago

Here is the ICS file I am using. And the code I'm running. samp.ics.log

And the PHP code:

use ICal\ICal;
$filename = "/Users/murraycollingwood/Downloads/samp.ics";
$data = file_get_contents($filename);
$struc = json_decode( $data, true );
if (isset($struc["SMSDirectoryData"]["timetables"])) {
    foreach ($struc["SMSDirectoryData"]["timetables"]["data"] as $teacher) {
        $staffcode = $teacher["teacher"];
        $icsData = $teacher["timetable"];

        $ical = new ICal();
        $ical->initString($icsData);
        $events = $ical->eventsFromRange(); 
        foreach ($events as $event) {
            print "event->dtstart_array[3] = " . $event->dtstart_array[3] . "\n";
            $dtstart = $ical->iCalDateToDateTime($event->dtstart_array[3], true);
            print "iCalDateToDateTime start = " . $dtstart->format('Y-m-d H:i:s') . "\n";
            $timestart = $dtstart->getTimestamp();
            print "getTimestamp start = " . $timestart . "\n";
            print "strftime start = " . strftime(MYSQL_DATE_TIME, $timestart) . "\n";
        }
    }
}
murraycollingwood commented 4 years ago

I think I have an idea. Could it be that when you getTimestamp() that you are using the timezone of the computer where the function is being run? My computer has php.ini setting of Australia/Brisbane which is 3 hours different to Pacific/Auckland and would explain the results I'm getting.

I'm suggesting the getTimestamp() should be using the timezone Auckland/Pacific as specified in the ICS file, not the local timezone of the machine processing.

Does that help?

s0600204 commented 4 years ago

Hi there! What you're seeing is expected behaviour given the input you're providing:

There is no such thing as a "local unix timestamp": a "unix timestamp" is, by its definition, always UTC. (https://en.wikipedia.org/wiki/Unix_time)

The reason why strftime() is giving you a version of the date and time based on your server's timezone - instead of the one specified in the ics file - is because that's what it does: it takes a (unix) timestamp and formats it based on "locale settings", which includes your server's timezone. (https://www.php.net/manual/en/function.strftime.php)

The DateTime object class and its getTimestamp() method are part of php, and are not added by the ics-parser. (https://www.php.net/manual/en/class.datetime.php)

And finally, $ical->icalDateToDateTime() only takes one argument. (It would be nice if php emitted a warning or caution when more arguments than expected are passed to a function/method, but it doesn't.)

murraycollingwood commented 4 years ago

Thanks s0600204, you are absolutely correct. The timestamp is correct. The strftime function was using my server's timezone to output the time in my Australia/Brisbane timezone. I modified my local timezone to Pacific/Auckland and the correct date and time popped out.

Thanks for your help.