The iCalendar spec provides the ability to define multiple timezones in a feed https://icalendar.org/iCalendar-RFC-5545/3-6-5-time-zone-component.html. This is important if you are using recurring events that span across daylight savings. Here is a good write up on the importance of VTIMEZONE objects in iCalendars. Also, recent observations seem to indicate that ical events imported into Outlook desktop client calendars, without VTIMEZONE objects, may not respect daylight savings time shifts, and end up displaying the incorrect time for events.

Below is an example of a timezone definition added to a eluceo/ical calendar object, It's basically adapted from the documentaation to use the current America/New_York timezone. It's rather verbose, and a version of this would be needed for every daylight savings/timezone in use.

      $tz  = 'America/New_York';
      $dtz = new \DateTimeZone($tz);

      // 2. Create timezone rule object for Daylight Standard Time
      $vTimezoneRuleStd = new \Eluceo\iCal\Component\TimezoneRule(\Eluceo\iCal\Component\TimezoneRule::TYPE_STANDARD);
      $vTimezoneRuleStd->setTzName('EST');
      $vTimezoneRuleStd->setDtStart(new \DateTime('2007-11-04 02:00:00', $dtz));
      $vTimezoneRuleStd->setTzOffsetFrom('-0400');
      $vTimezoneRuleStd->setTzOffsetTo('-0500');
      $stdRecurrenceRule = new \Eluceo\iCal\Property\Event\RecurrenceRule();
      $stdRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_YEARLY);
      $stdRecurrenceRule->setByMonth(11);
      $stdRecurrenceRule->setByDay('1SU');
      $vTimezoneRuleStd->setRecurrenceRule($stdRecurrenceRule);

      // 3. Create timezone rule object for Daylight Time
      $vTimezoneRuleDst = new \Eluceo\iCal\Component\TimezoneRule(\Eluceo\iCal\Component\TimezoneRule::TYPE_DAYLIGHT);
      $vTimezoneRuleDst->setTzName('EDT');
      $vTimezoneRuleDst->setDtStart(new \DateTime('2007-03-11 02:00:00', $dtz));
      $vTimezoneRuleDst->setTzOffsetFrom('-0500');
      $vTimezoneRuleDst->setTzOffsetTo('-0400');
      $dstRecurrenceRule = new \Eluceo\iCal\Property\Event\RecurrenceRule();
      $dstRecurrenceRule->setFreq(\Eluceo\iCal\Property\Event\RecurrenceRule::FREQ_YEARLY);
      $dstRecurrenceRule->setByMonth(3);
      $dstRecurrenceRule->setByDay('2SU');
      $vTimezoneRuleDst->setRecurrenceRule($dstRecurrenceRule);
      // 4. Create timezone definition and add rules
      $vTimezone = new \Eluceo\iCal\Component\Timezone($tz);
      $vTimezone->addComponent($vTimezoneRuleStd);
      $vTimezone->addComponent($vTimezoneRuleDst);
      $this->calendar->setTimezone($vTimezone);

Challenge for this module is finding a way to generate these entries in way that works for any provided time. We can't simply hard-code these values like the example does.

Using all times in UTC can sort of get around this problem. However, that seems to through off the logic for "All day" events. Making events appear to start at discrete times rather than using the "All day" feature, showing the event as a band across the top, provided by most calendar apps.

Issue fork views_ical-3092917

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

bburg created an issue. See original summary.

ekes’s picture

A super pragmatic note: I've not found an ical feed in the wild that includes the required VTIMEZONE section. I'm certain they exist as it is a must in the spec, but more often I've come across feeds that include the TZID none the less for each date-time, or include the non-standard X-WR-TIMEZONE for the whole feed.

ekes’s picture

> A super pragmatic note: I've not found an ical feed in the wild that includes the required VTIMEZONE section.

Going to have to update and retract that as I see Google Calendars ical invites now have them. And I don't know if this is new but the one I'm looking at seems to be confusing Lightning when it is imported.

bburg’s picture

Issue tags: +stable blocker

If I can get this resolved, I roll out the full release. This issue queue seems pretty quiet otherwise.

bburg’s picture

After years of this seemingly working without any problem, I think this issue is now popping up specifically with Outlook Desktop clients. I can subscribe to a calendar feed with just about any other service (Google, Apple, even the Outlook web app works fine) with events that look like this:

BEGIN:VEVENT
UID:20220216T121717-45420
DTSTART;TZID=America/New_York:20220422T100000
SEQUENCE:0
TRANSP:TRANSPARENT
DTEND;TZID=America/New_York:20220422T113000
SUMMARY:My event
CLASS:PUBLIC
DTSTAMP:20220421T212058Z
END:VEVENT

This event should appear on calendars as happening at 10:00 am on April 22nd. Instead I believe it's shown as happening at 11:00, if you subscribed to the calendar via the Outlook desktop app.

I tried running the feed I'm looking at through the validator at https://icalendar.org/validator.html, and I get several of these errors:

"Invalid TZID value or missing VTIMEZONE component (America/New_York) near line # 5
Reference: 3.2.19. Time Zone Identifier
Invalid TZID value or missing VTIMEZONE component (America/New_York) near line # 5
Reference: 3.2.19. Time Zone Identifier"
...

It seems to call out every event in the feed. Though line 5 corresponds with "BEGIN:VEVENT". So I assume it's calling out the whole object, rather than any specific line within the EVENT object itself. I also assume that it is inferring the Timezone based on the value used in the start and end dates themselves. Or it's complaining about the lack of the VTIMEZONE element altogether. I'm not really sure, but this is a confusing error message. Which brings me back to this issue...

I don't want to spend too much effort debugging this in the current state, since a lot of code is likely to change when we upgrade to eluceo/ical 2. issue here: #3209012: Move to eluceo/ical 2.0. But I am thinking that if we can somehow inform the IcalWizard style plugin of what timezones we need to use, then I think it shouldn't take much to add the VTIMEZONE component, which I am hoping will resolve this issue I'm seeing now.

It's been a while since I touched the code in this module, but I might need to look into it now, since a lot of people are getting confused about when their events are happening...

bburg’s picture

Suspiciously similar, albeit old issue reported here: #1460058: iCal feed not honoring timezone or Daylight Saving Time

bburg’s picture

It also looks like other people have noticed a change in Outlook starting this year. Here is an issue posted to the iCal library repository https://github.com/markuspoerschke/iCal/issues/367

Though this seems to be the opposite of what I am seeing now. They are seeing times showing in Daylight savings when they should not be, I am seeing times in Standard time when they should not.

The quickest workaround I believe for people seeing the issue is to just set your timezone override in the date field settings to UTC, which will render the times in UTC, and delegate whatever calendar app to sorting out the timezone. This seems ideal. As I don't have any clue how this module can be dynamic in a way to accommodate all timezones and their daylight savings variants (for those that continue with them).

I'm not really sure how enforce that at a code level. Since Drupal does some funny things with timezones before they typically reach you. Which leads to problems choosing what timezone to render in, when it's already been generated in something else.

So I might just update the documentation and make a strong recommendation that people make their field override the timezone into UTC.

bburg’s picture

Issue summary: View changes

I've spent some time over the last week looking into this issue. I've had success using the DateTime::getTransitions() return value to get the current defined timezone's daylight savings transitions, and using that to generate VTIMEZONE entries. But I have no idea on how to get the recurring rules for an arbitrary timezone. So I'm going to try to see if we can just add multiple entries for Daylight/standard times to cover all the defined events in the view response. What I have so far appears to pass the iCal validator, even with the duplicates. I suppose using recurring rules for these is just an alternative.

Since this constitutes a big change in the module's behavior, I think I make this a toggle-able option. The question though is whether this should be set on by default for existing installations. It doesn't seem like a good experience to find out your user's are late to their appointments, only to find out you need to go into the site and check some box. At the same time, I'm worried about rolling out the change to all existing installations, since test coverage on this module is non-existent.

Will create a branch in the next comment and push what I have to that.

Description updated a bit.

bburg’s picture

Issue summary: View changes
Status: Active » Needs review

Merge request patch available at https://git.drupalcode.org/project/views_ical/-/merge_requests/2.patch

If anyone else can test, please.

seantwalsh’s picture

Just tested the patch and it allowed my ical feed to validate which was a blocker for using the feed in a third-party. Here's the new section added post patch.

BEGIN:VTIMEZONE
TZID:America/New_York
X-LIC-LOCATION:America/New_York
BEGIN:DAYLIGHT
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
DTSTART:20220313T070000
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
DTSTART:20211107T060000
END:STANDARD
END:VTIMEZONE

Unfortunately, macOS doesn't support importing iCal so I can't test that bit at the moment.

"Support for importing and synchronizing for iCal is not yet available in Outlook for Mac."

bburg’s picture

Pushed an update to fix call to SmartDateTrait::isAllDay), we were passing a timezone object, when it should have been a string.

I haven't tested Mac Calendars, I'm surprised it doesn't work with the format. But I'll keep this open a bit longer for any other tests. I don't want to RTBC my own patch!

bburg’s picture

I went to add a location value to my iCal view today, and I ran into this error:

"An illegal choice has been detected. Please contact the site administrator."

The log showed this was pointing to the new VTIMEZONE checkbox added by this patch.

"Illegal choice 1 in Use VTIMEZONE element."

It seems that I was passing this checkbox field the options for the others, as if it was one of the other select lists. Leading to the situation where the "1" checked option didn't match the available options.

Patch coming later.

  • 4f6e649 committed on 3092917-support-vtimezone-objects
    Issue #3092917 by bburg: Support VTIMEZONE objects for daylight savings....
bburg’s picture

(Rebased with 8.x-1.x).

I'm going to do a few tests on a fresh install, but I think I'm going to go ahead and merge this, and tag a release.

  • bburg committed 326181a0 on 8.x-1.x
    Issue #3092917 by bburg: Support VTIMEZONE objects for daylight savings.
    
bburg’s picture

This is now available in the 8.x-1.0-alpha9 release.

bburg’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.