dmfs / lib-recur

A recurrence processor for Java
Apache License 2.0
199 stars 47 forks source link

Rule with timezone specification #26

Closed timopulkkinen closed 8 years ago

timopulkkinen commented 8 years ago

Hello,

Here's a rule that we are receiving from an another system/library: WKST=MO;FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR,SU;INTERVAL=1;BYHOUR=21;BYMINUTE=0;DTSTART=20161022T210000Z;TIMEZONE=Europe/Helsinki

The written version would be something like this: "Repeat on Mo,Tu,We,Th,Fr,Su at 21:00 EEST (+0300), starting from 22 Oct 2016 21:00:00 UTC".

Lib-recur seems to get a bit confused with timezones when parsing this rule and it produces occurrences such as 20161023T210000 (Mon Oct 24 00:00:00 EEST 2016).

Here's an example (Scala) code which I use to initialize the recurrence rule. val rr = new RecurrenceRule(rrule) val start = new DateTime(starting.getTimeInMillis) val rrIter = rr.iterator(start) if(rrIter.hasNext) rrIter.nextDateTime() ...

br, Timo

(I'm not entirely sure that if the rule we get from the another lib is actually standards compliant)

dmfs commented 8 years ago

The rule does not comply with RFC 5545 (see https://tools.ietf.org/html/rfc5545#page-39 for the valid parts). DTSTART and TIMEZONE are not valid parts of an RRULE. In an iCalendar file these are completely separate properties. When using a lax parser mode, lib-recur simply ignores these and always uses the start value you pass to iterator(DateTime).

Regarding the time zone issue: The instances are iterated in the time zone that your start value has. Since you're passing a DateTime in UTC, it does all the math in UTC and returns DateTime values in UTC. To iterate values in Europe/Helsinki use something like:

val rr = new RecurrenceRule(rrule)
// make sure start is represented in the local time zone
val start = new DateTime(TimeZone.getTimeZone("Europe/Helsinki"), starting.getTimeInMillis)
val rrIter = rr.iterator(start)
if(rrIter.hasNext)
    rrIter.nextDateTime() ...

Please note, that the correct time zone is important when iterating recurrence rules. Iterating in UTC does not adhere to DST changes that might occur in the local time zone.

timopulkkinen commented 8 years ago

Yes, I was suspecting that the format is not actually standards-compliant. It is actually a variant of rrule.js (Javascript library) that produces these. All right, thanks for your reply - I'll do some preparsing to the string.