Summary | CalDAV PUT parses multiple VTIMEZONE data incorrectly, even its own ones |
Queue | Synchronization |
Queue Version | FRAMEWORK_5_2 |
Type | Bug |
State | Assigned |
Priority | 1. Low |
Owners | jan (at) horde (dot) org |
Requester | skhorde (at) smail (dot) inf (dot) fh-bonn-rhein-sieg (dot) de |
Created | 02/17/2015 (3739 days ago) |
Due | |
Updated | 10/25/2023 (567 days ago) |
Assigned | 03/13/2015 (3715 days ago) |
Resolved | |
Milestone | |
Patch | No |
What is the status of your patch?
Since you had a look to the code and done some patches, perhaps you
can have a look to these issues as well?
15102 "import of ical with DAYLIGHT VTIMEZONE data results events
during standard time to be a hour early"
15149 "VTIMEZONE, RRULE => Hordes CalDAV subscription freezes
Thunderbird 115"
Best regards
Joerg wrote:
New Attachment: Test time 2-1.ics
(build 9) with Horde 5.2.22
BEGIN:VCALENDAR
VERSION:2.0
X-WR-CALNAME:Calendar
PRODID:-//The Horde Project//Horde iCalendar Library//EN
BEGIN:VEVENT
DTSTART;TZID=America/Los_Angeles:20220218T140000
DTEND;TZID=America/Los_Angeles:20220218T150000
DTSTAMP:20220216T231720Z
UID:216c1073-87ba-4a70-bf13-57eb4467065c
CREATED:20220216T223634Z
LAST-MODIFIED:20220216T225658Z
SUMMARY:Test time 2
ORGANIZER;CN=example@example.com:mailto:example@example.com
CLASS:PUBLIC
STATUS:CONFIRMED
TRANSP:OPAQUE
ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=example1@example.com:mailto:example1@example.com
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19180331T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3;UNTIL=19190330T100000Z
TZNAME:PDT
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
DTSTART:19181027T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=19191026T090000Z
TZNAME:PST
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19420209T030000
TZNAME:PWT
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:-0700
TZOFFSETTO:-0700
DTSTART:19450814T160000
TZNAME:PPT
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
DTSTART:19450930T020000
TZNAME:PST
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19480314T020100
TZNAME:PDT
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
DTSTART:19490101T020000
TZNAME:PST
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19500430T010000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=4;UNTIL=19660424T090000Z
TZNAME:PDT
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
DTSTART:19500924T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=9;UNTIL=19610924T090000Z
TZNAME:PST
END:STANDARD
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
DTSTART:19621028T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=19661030T090000Z
TZNAME:PST
END:STANDARD
BEGIN:STANDARD
TZOFFSETFROM:-0800
TZOFFSETTO:-0800
DTSTART:19671029T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=20061029T100000Z
TZNAME:PST
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19670430T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=4;UNTIL=19730429T100000Z
TZNAME:PDT
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19740106T030000
TZNAME:PDT
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19750223T030000
TZNAME:PDT
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19760425T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=4;UNTIL=19860427T100000Z
TZNAME:PDT
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:19870405T030000
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU;UNTIL=20060402T100000Z
TZNAME:PDT
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
DTSTART:20070311T030000
RRULE:FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=8,9,10,11,12,13,14;BYDAY=1SU
TZNAME:PDT
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
TZNAME:PST
END:STANDARD
END:VTIMEZONE
END:VCALENDAR
Horde_Icalendar 2.1.3 stable
still. The attachment contains what I PUT to the server and what I GET back.
New Attachment: patch-framework_Icalendar_lib_Horde_Icalendar_Vtimezone.php
The gmmktime() call has to use $year of the VEVENT for RRULEs without
UNTIL parameter to get the correct dates for the CET/CEST switch in
the year of the event and has to use $result['end'] for all RRULEs
with UNTIL parameter to calculate the correct switch dates for this
rules.
I reworked the patch to honor this.
Tested with em Client and Thunderbird/Lightning and seem to be okay.
Would be nice to see this committed as we soon start our internal
scheduling for the beginning of 2016.
Kind regards
Joerg
New Attachment: framework_Icalendar_lib_Horde_Icalendar_Vtimezone.php
Today i found some time to track this down.
Problem is the gmmktime() call in
framework/Icalendar/lib/Horde/Icalendar/Vtimezone.php (lines 154, 155).
Attached is a patch to fix this.
gmmktime is called with parameter $year which holds the year the event
actually occurs, instead $result['end'] should be used which holds the
year value of the RRULE UNTIL field.
Some background information:
Hint: Everything is related to timezone Europe/Berlin. It may may
affect other timezones too, but did no tests.
The problem is only visible every year for events between the 1st of
january and the real date for the switch to summertime (CEST), eg.
29th march 2015.
The CalDAV client has to do the following, which most clients ("em
Client" in my case) do:
GET url
the submitted isc file (framework/Icalendar/lib/Horde/Icalendar.php
line 1249).
For all entries without RRULE everything is fine and correctly parsed
and converted to timestamps, but RRULEs are completely wrong.
Here the example:
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19170416T020000
RRULE:FREQ=YEARLY;BYMONTH=4;BYMONTHDAY=15,16,17,18,19,20,21;BYDAY=1MO;UNTIL
=19180421T000000Z
TZNAME:CEST
END:DAYLIGHT
gmmktime(3, 0, 0, 4, 1, 2015) = 1427857200 = "Wed Apr 1 05:00:00 CEST 2015"
After further processing the value gets even worse to "Wed Apr 6
05:00:00 CEST 2015" but thats not relevant for demonstarting what
happens.
As the DTSTART is 19170416T020000 (something around -1663448400 as
timestamp)you get an $change_times array like this:
$change_times[0]['time']=-1663448400
$change_times[0]['from']=3600
$change_times[0]['to']=7200
$change_times[1]['time']=1427857200
$change_times[1]['from']=3600
$change_times[1]['to']=7200
The array is actually much larger but only those entries are relevant
as all other following entries are wrongly not used, see the following.
Now there is the comparison in
framework/Icalendar/lib/Horde/Icalendar.php line 1282:
if (($t >= $change_times[0]['time']) &&
($t < $change_times[0 + 1]['time'])) {
return $change_times[0]['to'];
Assume an event on "Thu Mar 26 08:00:00 CET 2015" which gmmktime'ed by
Horde itself "1427356800".
1427356800 >= -1663448400 && 1427356800 < 1427857200 -> return 7200
So you actually get an offest of 7200 instead of 3600 and the entry is
stored one hour off in the database and returned one hour off back to
the client during the next CalDAV GET request and also shown one hour
off in the Horde WebUI.
You can reproduce this for every year, as long as timezone
"Europe/Berlin" is used and the event is sometimes between 1st of
january and the real day of the switch from CET to CEST in this year.
I hope this is enough information to illustrate the root of the problem.
The attached patch is tested to work correctly.
A more complete and probably better solution would be to check the
actual year of the event against the year for every timezone rule and
only handle those rules that could affect the event and save some CPU
cycles not processing rules from decades in the past ever and ever
again, but that's another story.
Kind regards
Joerg
Assigned to Jan Schneider
New Attachment: caldav_vtimezone_bug13866.patch.bz2
in $year-1.
With RRULE only one $result is returned, the entry of $year. So, if
the caller wants to know the timezone for the 2nd Feb 2015, the
timestamps of daylight and standard time of _2015_ are returned, which
neither does apply! Daylight is in March, standard in Oct.
Attached patch returns the entry for $year and $year-1 for RRULE, too.
Which is not 100% correct either, but mimmicks the idea of RDATE and
will cover the situation I faced right now.
It does not work to delete some other pair, it does not work to delete
just one of them.
BEGIN:DAYLIGHT
TZNAME:CEMT
TZOFFSETFROM:+0200
TZOFFSETTO:+0300
DTSTART:19450524T020000
RDATE;VALUE=DATE-TIME:19450524T020000
RDATE;VALUE=DATE-TIME:19470511T030000
END:DAYLIGHT
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0300
TZOFFSETTO:+0200
DTSTART:19450924T030000
RDATE;VALUE=DATE-TIME:19450924T030000
RDATE;VALUE=DATE-TIME:19470629T030000
END:DAYLIGHT
=======================
BEGIN:VCALENDAR
PRODID:-//K Desktop Environment//NONSGML libkcal 4.3//EN
VERSION:2.0
X-KDE-ICAL-IMPLEMENTATION-VERSION:1.0
BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19810329T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
END:DAYLIGHT
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19160430T230000
RDATE;VALUE=DATE-TIME:19160430T230000
RDATE;VALUE=DATE-TIME:19170416T020000
RDATE;VALUE=DATE-TIME:19180415T020000
RDATE;VALUE=DATE-TIME:19400401T020000
RDATE;VALUE=DATE-TIME:19430329T020000
RDATE;VALUE=DATE-TIME:19440403T020000
RDATE;VALUE=DATE-TIME:19450402T020000
RDATE;VALUE=DATE-TIME:19460414T020000
RDATE;VALUE=DATE-TIME:19470406T030000
RDATE;VALUE=DATE-TIME:19480418T020000
RDATE;VALUE=DATE-TIME:19490410T020000
RDATE;VALUE=DATE-TIME:19800406T020000
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19800928T030000
RRULE:FREQ=YEARLY;COUNT=16;BYDAY=-1SU;BYMONTH=9
END:STANDARD
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19961027T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
END:STANDARD
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19161001T010000
RDATE;VALUE=DATE-TIME:19161001T010000
RDATE;VALUE=DATE-TIME:19170917T030000
RDATE;VALUE=DATE-TIME:19180916T030000
RDATE;VALUE=DATE-TIME:19421102T030000
RDATE;VALUE=DATE-TIME:19431004T030000
RDATE;VALUE=DATE-TIME:19441002T030000
RDATE;VALUE=DATE-TIME:19451118T030000
RDATE;VALUE=DATE-TIME:19461007T030000
RDATE;VALUE=DATE-TIME:19471005T030000
RDATE;VALUE=DATE-TIME:19481003T030000
RDATE;VALUE=DATE-TIME:19491002T030000
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:CEMT
TZOFFSETFROM:+0200
TZOFFSETTO:+0300
DTSTART:19450524T020000
RDATE;VALUE=DATE-TIME:19450524T020000
RDATE;VALUE=DATE-TIME:19470511T030000
END:DAYLIGHT
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0300
TZOFFSETTO:+0200
DTSTART:19450924T030000
RDATE;VALUE=DATE-TIME:19450924T030000
RDATE;VALUE=DATE-TIME:19470629T030000
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20150213T133358Z
CREATED:20150213T133358Z
UID:a2b4e780-195e-4b8c-bd71-0c674794b5ab
LAST-MODIFIED:20150218T141422Z
SUMMARY:korg 14:00 $t
DTSTART;TZID=Europe/Berlin:20150217T140000
DTEND;TZID=Europe/Berlin:20150217T150000
TRANSP:OPAQUE
BEGIN:VALARM
DESCRIPTION:
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
X-KDE-KCALCORE-ENABLED:TRUE
END:VALARM
END:VEVENT
END:VCALENDAR
Priority ⇒ 1. Low
State ⇒ Unconfirmed
Patch ⇒ No
Milestone ⇒
Queue ⇒ Synchronization
Summary ⇒ CalDAV PUT parses multiple VTIMEZONE data incorrectly, even its own ones
Type ⇒ Bug
seems to be the number of timezone entries only.
kronolith 4.2.5 stable
Horde_Timezone 1.0.9 stable
Horde_Dav 1.1.2 stable
pear install HTTP_WebDAV_Server
pear/HTTP_WebDAV_Server is already installed and is the same as the
released version 1.0.0RC8
If I re-upload an event from CalDAV:
GET url
PUT url
GET url
url is
horde/rpc.php/calendars/uid/calendar~PEjFLdNBNhUO66MpM2Dlew5/1423834453.R724.ics
The time of the 2nd GET is 1 hour louer than on the 1st GET. My
default timezone is GMT+1, so I guess the PUT parses the time as UTC.
Below you'll find the content of the 2nd GET. If you strip all
TIMEZONE entries, but these two ones:
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19810329T010000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19961027T010000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:CET
END:STANDARD
END:VTIMEZONE
To re-upload the event via PUT does _not_change the time. So it seems
that other timezone definitions confuse the CalDAV parser. I have the
same problem with the KDE Korganizer v4.14.2, because it also uploads
many timezone entries, but _not_ with Lightning, which uploads only
the two effective ones above.
BEGIN:VCALENDAR
VERSION:2.0
X-WR-CALNAME:Calendar of dvtest6
PRODID:-//The Horde Project//Horde iCalendar Library//EN
BEGIN:VEVENT
DTSTART;TZID=Europe/Berlin:20150217T140000
DTEND;TZID=Europe/Berlin:20150217T150000
DTSTAMP:20150217T104721Z
UID:a2b4e780-195e-4b8c-bd71-0c674794b5ab
CREATED:20150213T133323Z
LAST-MODIFIED:20150217T104721Z
SUMMARY:perl 15:00 1424169619
CLASS:PUBLIC
STATUS:CONFIRMED
TRANSP:OPAQUE
END:VEVENT
BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19160430T230000
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19161001T010000
TZNAME:CE-T
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19170416T020000
RRULE:FREQ=YEARLY;BYMONTH=4;BYMONTHDAY=15,16,17,18,19,20,21;BYDAY=1MO;UNTIL
=19180421T000000Z
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19170917T020000
RRULE:FREQ=YEARLY;BYMONTH=9;BYMONTHDAY=15,16,17,18,19,20,21;BYDAY=1MO;UNTIL
=19180915T000000Z
TZNAME:CE-T
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19400401T020000
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19421102T020000
TZNAME:CE-T
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19430329T020000
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19431004T020000
TZNAME:CE-T
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19440403T020000
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1MO;UNTIL=19450401T010000Z
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19441002T020000
TZNAME:CE-T
END:STANDARD
BEGIN:STANDARD
TZOFFSETFROM:+0100
TZOFFSETTO:+0100
DTSTART:19450916T020000
TZNAME:CE-T
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0300
DTSTART:19450524T020000
TZNAME:CEMT
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:+0300
TZOFFSETTO:+0200
DTSTART:19450924T030000
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19451118T020000
TZNAME:CE-T
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19460414T020000
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19461007T020000
TZNAME:CE-T
END:STANDARD
BEGIN:STANDARD
TZOFFSETFROM:+0100
TZOFFSETTO:+0100
DTSTART:19471005T020000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19491002T010000Z
TZNAME:CE-T
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19470406T030000
TZNAME:CEST
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:+0200
TZOFFSETTO:+0300
DTSTART:19470511T020000
TZNAME:CEMT
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:+0300
TZOFFSETTO:+0200
DTSTART:19470629T030000
TZNAME:CEST
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:+0200
TZOFFSETTO:+0200
DTSTART:19480418T020000
TZNAME:CEST
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:+0200
TZOFFSETTO:+0200
DTSTART:19490410T020000
TZNAME:CEST
END:DAYLIGHT
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19800406T010000
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU;UNTIL=19800406T000000Z
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19800928T010000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=9;UNTIL=19950923T230000Z
TZNAME:CE-T
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19810329T010000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
TZNAME:CEST
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19961027T010000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:CE-T
END:STANDARD
END:VTIMEZONE
END:VCALENDAR