Menu

Recurring event : How to give a DTTSTART which is not the first occurence ?

Help
2014-01-03
2018-12-16
  • Quentin Bérard

    Quentin Bérard - 2014-01-03

    Hello,
    I have a small problem in the use of rrule with iCal4j (it's not a iCal4j issue)

    My need is :
    1- let a user choose a recurrence on a website (weekly for example)
    2- run an action each day the recurrence occure.

    For the part 1, I have found this jquery plugin : https://github.com/collective/jquery.recurrenceinput.js
    It give me the rrule part of the ical standard, and a start date (which is not necessarily the date of the first occurrence).

    For example :
    - rrule = "FREQ=WEEKLY;COUNT=2;BYDAY=MO"
    -> each monday for 2 week
    - start is January,3 2014

    And the occurence are :
    - 06-01-2014
    - 13-01-2014

    Part 2 : So I search to read this rule, and found iCal4j.
    I have managed to create a VEvent with my 2 data :

    Date startDate = new Date();
    String rrule = "FREQ=WEEKLY;COUNT=2;BYDAY=MO";
    // initialise as an all-day event
    VEvent event = new VEvent(new net.fortuna.ical4j.model.Date(startDate), "bla bla");
    // adding rrule
    event.getProperties().add(new RRule(rrule));
    

    It's generate :

    BEGIN:VEVENT
    DTSTAMP:20140103T190354Z
    DTSTART;VALUE=DATE:20140103
    SUMMARY:bla bla
    RRULE:FREQ=WEEKLY;COUNT=2;BYDAY=MO
    END:VEVENT
    

    When I use this code :

    Calendar calEnd = Calendar.getInstance();
    calEnd.set(Calendar.YEAR, 3000);
    
    DateTime start = new DateTime(event.getStartDate().getDate());
    DateTime end = new DateTime(calEnd.getTime());
    Period period = new Period(start, end);
    PeriodList r = event.calculateRecurrenceSet(period);
    
    for (Period p : (Iterable<Period>) r) {
        System.out.println(" - " + s.format(d));
    }
    

    I see :
    - 03-01-2014
    - 06-01-2014
    - 13-01-2014

    Note that I have asked for COUNT=2 and the first day is not a monday !

    ical4j has a correct behavior because I don't satisfy the ical specification.

    Actually, the rfc2445 (4.8.5.1) explain that The "DTSTART" property defines the first instance in the recurrence set.

    And in my case it's not.

    I don't want to compute it, almost all the work is already done by ical4j

    But how can I manage in order to having what I want ?

    I have 2 idea : compute it with ical 4j.

    Maybe something like this (insipred by Component.calculateRecurrenceSet() )

    final DateTime startMinusDuration = new DateTime(period.getStart());
        startMinusDuration.setTime(rDuration.negate().getTime(
                period.getStart()).getTime());
    Iterator i = getProperties(Property.RRULE).iterator()
    final RRule rrule = (RRule) i.next();
    final DateList rruleDates = rrule.getRecur().getDates(start.getDate(),
                    new Period(startMinusDuration, period.getEnd()), startValue);
    Iterator j = rruleDates.iterator()
    Date rruleDate = (Date) j.next();
    

    which could give me that date ... but I'm not sure

    But when I look at this method code closely (Component.calculateRecurrenceSet()), I saw that the "bad" date is added here :

    if (period.intersects(startPeriod)) {
        recurrenceSet.add(startPeriod);
    }
    

    And it's one of the only line not documented ! (The code is usually very well documented :) )
    And I don't understand it's purpose.

    What happened if I remove this line ?

    What is your opinion about my problem ?

    Thanks for reading.

    PS : note that the python library python-dateutil have the rrulestr function.
    It's default behavior is to not respect the rfc, and do not add the DTTSTART date !!
    -> see this option : compatible
    If set to True, the parser will operate in RFC-compatible mode. Right now it means that unfold will be turned on, and if a DTSTART is found, it will be considered the first recurrence instance, as documented in the RFC.

    http://labix.org/python-dateutil#head-e987b581aebacf25c7276d3e9214385a12a091f2

     

    Last edit: Quentin Bérard 2014-01-06
  • Ben Fortuna

    Ben Fortuna - 2014-01-06

    Hi Quentin,

    It has been a while since writing this code, so I had to have another look to understand it myself. ;) As you pointed out, the RFC states that the DTSTART property should define the first instance in the recurrence set, as specified here:

    http://tools.ietf.org/search/rfc5545#section-3.8.5.3

    You will notice the description has changed slightly in rfc5545 (an update to rfc2445), and states that "The recurrence set generated with a "DTSTART" property value not synchronized with the recurrence rule is undefined." So I think that means it is up to the implementation what to do when the DTSTART value doesn't match the RRULE formula, but it is preferred that the DTSTART value conforms to the RRULE.

    This may give us the option of excluding the DTSTART value from the recurrence set, but for now if the specified period intersects with the event at all, the DTSTART value will be added to the recurrence set.

    For now I think your only options are to ensure the DTSTART value is a Monday (i.e. the first monday following your current DTSTART value), or alternatively remove the first value from the calculated recurrence set if it is not a Monday.

    I will make a note that we may want to change this behaviour based on rfc5445 in the future.

    regards,
    ben

     
  • Quentin Bérard

    Quentin Bérard - 2014-01-06

    Thanks for your answer.

    I haven't seen rfc 5545, so you can maybe choose to adopt the same behavior/option than the python library.

    I have given an example with this simple rule, but in fact, the end user choose the rule and I don't want to parse myself the rrule in order to check if I must or not include DTSTART. This will be so many code, with potential errors. And I don't know closely enough ical4j to use it.

    For now, I'll simply try to remove those 3 lines :

    if (period.intersects(startPeriod)) {
        recurrenceSet.add(startPeriod);
    }
    

    And then do some tests.

    Regards
    Quentin

     

    Last edit: Quentin Bérard 2014-01-06
  • Quentin Bérard

    Quentin Bérard - 2014-01-13

    I have done many unit tests, and all work as I want when I remove those 3 lines :
    the DTSTART is not added to the recurrence when it's not an occurrence of this recurrence.

     
  • Ben Fortuna

    Ben Fortuna - 2018-12-16

    Fix will be applied in next release (v3.0.5)

     

Log in to post a comment.

MongoDB Logo MongoDB