spatie / calendar-links

Generate add to calendar links for Google, iCal and other calendar systems
https://spatie.be/opensource
MIT License
914 stars 149 forks source link

ics generated with the allDay option "ends before the start" when opening in Outlook #53

Closed freakpants closed 5 years ago

freakpants commented 5 years ago

Issue

When i create a link using the ics() Method, the created ics File, when opened in Outlook, correctly displays an all day event. However, the end date is displayed as one day before the start.

Screenshot

Raw Ics Data

data:text/calendar;charset=utf8,BEGIN:VCALENDAR%0d%0aVERSION:2.0%0d%0aBEGIN:VEVENT%0d%0aUID:99199f9561c8aabcd2d70b311def287e%0d%0aSUMMARY:Title of Event%0d%0aDTSTART:20190114%0d%0aDTEND:20190114%0d%0aDESCRIPTION:Description of Event%0d%0aEND:VEVENT%0d%0aEND:VCALENDAR

Reproduction

// set the timezone to our local environment               
date_default_timezone_set("Europe/Zurich");
$from = DateTime::createFromFormat('Y-m-d', '2019-01-14');
$to = DateTime::createFromFormat('Y-m-d', '2019-01-14');
$to->modify('+1 day');

$link = Link::create('Title of Event', $from, $to, true)->description('Description of Event');
$ics = $link->ics();

Environment

Laravel 5.5, PHP 7.2.11, xampp on Windows 10, spatie/calendar-links 1.2

Conclusion

I've been testing back and forth for a couple of hours, and have come to the realization that the following lines in Link.php cause the issue for outlook:

if ($this->allDay) {
    $this->from = clone $from;
    $this->to = clone $from;
}

Removing these lines, and feeding in a date that is +1day from the start, fixes this behaviour, at least for Outlook. Google Calendar was already correctly handling these ics files, and is also handling the file generated this way correctly. Outlook seems to consider all-day events events that start at 00:00:00 of the day, and end at 00:00:00 of the next day.

From my testing, the issue is not related to timezones or daylight savings.

alies-dev commented 5 years ago

@freakpants Thanks for the report!

This is what I found in specs

The "DTSTART" property for a "VEVENT" specifies the inclusive
      start of the event.  For recurring events, it also specifies the
      very first instance in the recurrence set.  The "DTEND" property
      for a "VEVENT" calendar component specifies the non-inclusive end
      of the event.  For cases where a "VEVENT" calendar component
      specifies a "DTSTART" property with a DATE value type but no
      "DTEND" nor "DURATION" property, the event's duration is taken to
      be one day.  For cases where a "VEVENT" calendar component
      specifies a "DTSTART" property with a DATE-TIME value type but no
      "DTEND" property, the event ends on the same calendar date and
      time of day specified by the "DTSTART" property.

So, I think the best choice is to use DURATION instead of DTEND.

@freakpants Could you please test this link and try to import this event to outlook?

data:text/calendar;charset=utf8,BEGIN:VCALENDAR%0d%0aVERSION:2.0%0d%0aBEGIN:VEVENT%0d%0aUID:25b6beee84a28151f50feb440f5c1097%0d%0aSUMMARY:Birthday%0d%0aDTSTART:20180201%0d%0aDURATION:P1D%0d%0aDESCRIPTION:With balloons\\, clowns and stuff\\nBring a dog\\, bring a frog%0d%0aLOCATION:Party Lane 1A\\, 1337 Funtown%0d%0aEND:VEVENT%0d%0aEND:VCALENDAR
freakpants commented 5 years ago

Seems to work. image