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

Support for DST in RRULES #109

Closed
SSzretter opened this issue Mar 19, 2017 · 12 comments
Closed

Support for DST in RRULES #109

SSzretter opened this issue Mar 19, 2017 · 12 comments

Comments

@SSzretter
Copy link

SSzretter commented Mar 19, 2017

I am downloading ics data from Google calendar and non-recurring events appear ok with the correct time, but recurring events are off by 1 hour. I am setting the timezone in my php and turning on $useTimeZoneWithRRules at least puts my times within 1 hour (with this set to false it was 6 hours off). Changing the time zones between EST and EST5EDT and America/New York makes no difference to the output (I tried passing false to the iCalDateToUnixTimestamp).

So I am thinking either something is broken with the parsing of this Google calendar RRULES, or it needs a way to account for DST, or possibly I have to change a setting?

date_default_timezone_set('EST5EDT');  // I have tried America/New York also
ini_set("date.timezone", "EST5EDT");
if (date('I', time()))
    echo 'We’re in DST!';  // **** WE ARE IN DST
else
    echo 'We’re not in DST!';

$ical = new ICal();
$ical->useTimeZoneWithRRules=true;
$ical->initURL('google calendar ics url');
$events = $ical->sortEventsWithOrder($ical->eventsFromInterval('3 days'));`
foreach ($events as $event)
{
    $start = date("Y-m-d h:i:s",$ical->iCalDateToUnixTimestamp($event->dtstart, true));  
    $end = date("Y-m-d h:i:s",$ical->iCalDateToUnixTimestamp($event->dtend, true)); 
    echo $start;
    echo $end;
}
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:XXXTEST
X-WR-TIMEZONE:America/New_York
X-WR-CALDESC:
BEGIN:VTIMEZONE
TZID:America/New_York
X-LIC-LOCATION:America/New_York
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=America/New_York:20170313T080000
DTEND;TZID=America/New_York:20170313T110000
RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR
DTSTAMP:20170319T130024Z
UID:XXXptseqtmp07al34@google.com
CREATED:20170318T203731Z
DESCRIPTION:
LAST-MODIFIED:20170318T223849Z
LOCATION:
SEQUENCE:2
STATUS:CONFIRMED
SUMMARY:Scott recur mwf
TRANSP:OPAQUE
END:VEVENT
BEGIN:VEVENT
DTSTART:20170318T120000Z
DTEND:20170318T130000Z
DTSTAMP:20170319T130024Z
UID:XXXkctlj90qg8@google.com
CREATED:20170318T211306Z
DESCRIPTION:
LAST-MODIFIED:20170318T220751Z
LOCATION:
SEQUENCE:1
STATUS:CONFIRMED
SUMMARY:test2
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
@u01jmg3 u01jmg3 self-assigned this Mar 19, 2017
@u01jmg3 u01jmg3 changed the title Support for DST in RRULES ? Support for DST in RRULES Mar 19, 2017
@u01jmg3
Copy link
Owner

u01jmg3 commented Mar 19, 2017

I believe this may be related to #105 - I have a fix coming so if you could try that once I release v2.0.3. It all relates to timezone settings.

@u01jmg3 u01jmg3 added the bug label Mar 19, 2017
@u01jmg3 u01jmg3 added this to the v2.x.x milestone Mar 19, 2017
@u01jmg3
Copy link
Owner

u01jmg3 commented Mar 20, 2017

Fixed by the release of v2.0.3

@u01jmg3 u01jmg3 closed this as completed Mar 20, 2017
@u01jmg3 u01jmg3 removed their assignment Mar 20, 2017
@u01jmg3 u01jmg3 added bug-normal and removed bug labels Mar 20, 2017
@SSzretter
Copy link
Author

SSzretter commented Mar 20, 2017

I am not sure exactly what is wrong, but now after updating the library I am getting back these date/times:

2017-03-20 00:00:00  // $start = date("Y-m-d H:i:s",$ical->iCalDateToUnixTimestamp($event->dtstart, true))
2017-03-20 03:00:00 // $end = date("Y-m-d H:i:s",$ical->iCalDateToUnixTimestamp($event->dtend, true))

$ical->dtstart is 20170320T040000
$ical->dtend is 20170320T070000

The original google event is 8a-11a (America/New_York) FYI.

@u01jmg3
Copy link
Owner

u01jmg3 commented Mar 20, 2017

@SSzretter
Copy link
Author

SSzretter commented Mar 20, 2017

Ok - getting closer. So now if I set $ical->useTimeZoneWithRRules=false; and use your sample code using date object my recurring events are coming back with the correct times (8a-11a EST). I had to set that to false or it was still not returning the correct times.

However now my non-recurring event is now coming back with the incorrect time. The non-recurring event was in the sample ics I posted earlier and now it comes back with 12:00:00 - 13:00:00 instead of 08:00:00 - 09:00:00. So it is as if something is not working for the timezone for non-recurring in this scenario.

This is the code I use now based on what you sent me:

$dtstart = new DateTime('@' . (int) $ical->iCalDateToUnixTimestamp($event->dtstart));
$start   = $dtstart->format('Y-m-d H:i:s');
$dtend   = new DateTime('@' . (int) $ical->iCalDateToUnixTimestamp($event->dtend));
$end     = $dtend->format('Y-m-d H:i:s');

u01jmg3 added a commit that referenced this issue Mar 21, 2017
…lDateWithTimeZone()` unless Zulu time has been specified
@u01jmg3
Copy link
Owner

u01jmg3 commented Mar 21, 2017

  • Use the constructor to override settings such as $useTimeZoneWithRRules
  • For your non-recurring event, do not finalise DTSTART / DTEND with Z as the calendar timezone will not be applied
    • The reason for this is that it signifies Zulu time which means UTC
    • Use dev-master to pull in the fix I created for making use of the calendar timezone when Z is not present: a512c63
      • (This will get your non-recurring event working as you expect it to)
  • If you want to use start and end times with timezones applied, I suggest using dtstart_tz / dtend_tz as per the snippet below
    • Worth noting that having $useTimeZoneWithRRules set to true will only apply the timezone to recurrence events and won't apply it to the parent recurrence event or any non-recurring events for the keys dstart and dtend
      • (This is why I suggested using dtstart_tz / dtend_tz to better fit your requirements)

$dtstart_tz = new DateTime('@' . (int) $ical->iCalDateToUnixTimestamp($event->dtstart_tz));
$start      = $dtstart_tz->format('Y-m-d H:i:s');
$dtend_tz   = new DateTime('@' . (int) $ical->iCalDateToUnixTimestamp($event->dtend_tz));
$end        = $dtend_tz->format('Y-m-d H:i:s');

@SSzretter
Copy link
Author

SSzretter commented Mar 21, 2017

No difference this morning when I tried the updated code, changed to the new constructor and used the dtstart_tz / dtend_tz. In fact, when I use those _tz fields it seems to pull the same time (not adjusting for timezone) regardless of any other setting. So even if I change the $useTimeZoneWithRRules the recurring events show as 4a-7a instead of 8a-11a. If I use the $event->dtstart (non-tz version), the recurring events look good with $useTimeZoneWithRRules set to false. However in all cases I currently do not seem to be able to get the non-recurring event to show the correct time no matter which settings or field I use. It shows 12:00:00 and 13:00:00 (but should be 8a-9a).

One question I do have - you mentioned for the non-recurring event 'do not finalise DTSTART / DTEND with Z'... What do you mean by that? Google is adding the Z (I included the link to the ics coming from google if you want to look at that)...

Here is a more complete sample of my current code. There is one non-recurring event from 8a-9a and a M/W/F recurring from 8a-11a my time zone (EST).

date_default_timezone_set('America/New_York');
ini_set("date.timezone", 'America/New_York');

$folder_id="https://calendar.google.com/calendar/ical/l0isqaou87j5hrha1eu2oac9jo%40group.calendar.google.com/public/basic.ics";

$ical = new ICal($folder_id, array(
    'defaultSpan'           => 2,
    'defaultWeekStart'      => 'MO',
    'useTimeZoneWithRRules' => false,
));


$events = $ical->sortEventsWithOrder($ical->eventsFromInterval('3 days'));
$out='';
if ($events) {
    foreach ($events as $event) {
        $subject = $event->summary;
        $id = $event->uid;
        
        $dtstart = new DateTime('@' . (int) $ical->iCalDateToUnixTimestamp($event->dtstart));  // _tz here does not work
        $start = $dtstart->format('Y-m-d H:i:s');
        $dtend = new DateTime('@' . (int) $ical->iCalDateToUnixTimestamp($event->dtend));   // _tz here does not work
        $end = $dtend->format('Y-m-d H:i:s');
        $location = $event->location;
        $out.= "<response>";
        $out.= "<subject>$subject</subject>";
        $out.= "<location>$location</location>";
        $out.= "<dtstart>$start</dtstart>";
        $out.= "<dtend>$end</dtend>";
        $out.= "<id>$id</id>";
        $out.= "<priority>0</priority>";
        $out.= "</response>";
    } //for each
}
echo $out;

It currently produces this - you can see the recurring event is correct with the code above, but the non-recurring event has the incorrect time (not adjusted for time zone). I tried using the dtstart_tz / dtend_tz fields and that did not help and in fact did not work for the recurring event.

<response>
    <subject>test2</subject>
    <location></location>
    <dtstart>2017-03-21 12:00:00</dtstart>
    <dtend>2017-03-21 13:00:00</dtend>
    <id>uqnt090jvr0en3cqkctlj90qg8@google.com</id>
    <priority>0</priority>
</response>
<response>
    <subject>Scott recur mwf</subject>
    <location></location>
    <dtstart>2017-03-22 08:00:00</dtstart>
    <dtend>2017-03-22 11:00:00</dtend>
    <id>9huhq46274rrptseqtmp07al34@google.com</id>
    <priority>0</priority>
</response>

@u01jmg3
Copy link
Owner

u01jmg3 commented Mar 21, 2017

  • Each time I answer your question I am having to edit your markdown before I can read what you have put.
    • Please preview your response before commenting so it is readable.
  • Enclose code in 3 backticks to create a code block.

    ```
    Your code here
    ```


Google is adding the Z

  • Okay, I have created a method for forcing the timezone when populating dtstart_tz / dtend_tz - see 9b2d1bc

    • Please therefore use the latest dev-master
  • I have amended your code:

    date_default_timezone_set('America/New_York');
    ini_set('date.timezone', 'America/New_York');
    
    $filename = 'https://calendar.google.com/calendar/ical/l0isqaou87j5hrha1eu2oac9jo%40group.calendar.google.com/public/basic.ics';
    
    $ical = new ICal($filename, array(
        'defaultSpan'           => 2,
        'defaultWeekStart'      => 'MO',
        'useTimeZoneWithRRules' => false,
    ));
    
    $events = $ical->eventsFromInterval('3 days');
    $out = '';
    if ($events) {
        foreach ($events as $event) {
            $subject  = $event->summary;
            $id       = $event->uid;
            $dtstart  = new DateTime('@' . (int) $ical->iCalDateToUnixTimestamp($event->dtstart_tz));
            $start    = $dtstart->format('Y-m-d H:i:s');
            $dtend    = new DateTime('@' . (int) $ical->iCalDateToUnixTimestamp($event->dtend_tz));
            $end      = $dtend->format('Y-m-d H:i:s');
            $location = $event->location;
            $out     .= "<response>\n";
            $out     .= "\t<subject>$subject</subject>\n";
            $out     .= "\t<location>$location</location>\n";
            $out     .= "\t<dtstart>$start</dtstart>\n";
            $out     .= "\t<dtend>$end</dtend>\n";
            $out     .= "\t<id>$id</id>\n";
            $out     .= "\t<priority>0</priority>\n";
            $out     .= "</response>\n";
        }
    }
    
    $out = htmlspecialchars($out);
    echo "<pre>{$out}</pre>";
  • Which correctly produces:

    <response>
    	<subject>test2</subject>
    	<location></location>
    	<dtstart>2017-03-21 08:00:00</dtstart>
    	<dtend>2017-03-21 09:00:00</dtend>
    	<id>uqnt090jvr0en3cqkctlj90qg8@google.com</id>
    	<priority>0</priority>
    </response>
    <response>
    	<subject>Scott recur mwf</subject>
    	<location></location>
    	<dtstart>2017-03-22 04:00:00</dtstart>
    	<dtend>2017-03-22 07:00:00</dtend>
    	<id>9huhq46274rrptseqtmp07al34@google.com</id>
    	<priority>0</priority>
    </response>

@SSzretter
Copy link
Author

Your output for the non-recurring "test2" is correct at 8a-9a, but the recur mwf should be 8a-11a (not 4a-7a).

image

u01jmg3 added a commit that referenced this issue Mar 21, 2017
@u01jmg3
Copy link
Owner

u01jmg3 commented Mar 21, 2017

  • Using latest dev-master I get:
<response>
	<subject>test2</subject>
	<location></location>
	<dtstart>2017-03-21 08:00:00</dtstart>
	<dtend>2017-03-21 09:00:00</dtend>
	<id>uqnt090jvr0en3cqkctlj90qg8@google.com</id>
	<priority>0</priority>
</response>
<response>
	<subject>Scott recur mwf</subject>
	<location></location>
	<dtstart>2017-03-22 08:00:00</dtstart>
	<dtend>2017-03-22 11:00:00</dtend>
	<id>9huhq46274rrptseqtmp07al34@google.com</id>
	<priority>0</priority>
</response>

@SSzretter
Copy link
Author

Looks good now, thank you

@u01jmg3
Copy link
Owner

u01jmg3 commented Mar 21, 2017

Spot anything else just let me know - realise this has been a slog but I appreciate your help in fine tuning the parser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants