Subject: [Ietf-calsify] FREQ=MONTHLY when DTSTART = 29/30/31st.

From: Nigel.Swinson at rockliffe.com (Nigel Swinson)
Date: Mon Feb 19 16:01:10 2007

Please could you confirm to me that the following does not include the 15th of February:

DTSTART;VALUE=DATE:20070130
RRULE:FREQ=MONTHLY;BYMONTHDAY=15,30

Nor does this include any date in February:

DTSTART;VALUE=DATE:20070130
RRULE:FREQ=MONTHLY;BYMONTHDAY=1,-1

Whereas these would:

DTSTART;VALUE=DATE:20070115
RRULE:FREQ=MONTHLY;BYMONTHDAY=15,30
EXDATE:20070115
 
DTSTART;VALUE=DATE:20070130
RRULE:FREQ=DAILY;BYMONTHDAY=15,30

I don't find the above particularly obvious, so in case it helps, my thinking is that you use DTSTART and FREQ to create the initial recurrence set, and then refine/expand it using the BYXXX rules.  As there is no 30th of Feb, the initial recurrence set contains no dates in February, and hence we have no date in february to expand or refine to create additional dates in february in the context of a monthly rule.

If I am right, and you also consider the above not particularly obvious, perhaps it worth refining this paragraph in RFC2445 to spell out the algorithm.  I suggest we move the "invalid date" paragraph down one, and then:

http://tools.ietf.org/html/draft-ietf-calsify-rfc2445bis-05#section-3.3.10

      Information, not contained in the rule, necessary to determine the
      various recurrence instance start time and dates are derived from
      the Start Time ("DTSTART") component attribute.  For example,
      "FREQ=YEARLY;BYMONTH=1" doesn't specify a specific day within the
      month or a time.  This information would be the same as what is
      specified for "DTSTART".

      Recurrence rules may generate recurrence instances with invalid
      date (e.g., February 30) or nonexistent local time (e.g., 1:30 AM
      on a day where the local time is moved forward by an hour at 1:00
      AM).  Such recurrence instances MUST be ignored and MUST NOT be
      counted as part of the recurrence set.
+    Should the combination of DTSTART and FREQ itself create
+    recurrences that lie on non existant dates, then you end up skipping
+    entire intervals.  For example "DTSTART;VALUE=DATE:20070130" with
+    "FREQ=MONTHLY" will never contain any instances in February regardless
+    of what BYXXX rule parts are specified.

      If multiple BYxxx rule parts are specified, then after evaluating
      the specified FREQ and INTERVAL rule parts, the BYxxx rule parts
      are applied to the current set of evaluated occurrences in the
      following order: BYMONTH, BYWEEKNO, BYYEARDAY, BYMONTHDAY, BYDAY,
      BYHOUR, BYMINUTE, BYSECOND and BYSETPOS; then COUNT and UNTIL are
      evaluated.

Cheers

Nigel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.osafoundation.org/pipermail/ietf-calsify/attachments/20070220/ce92069f/attachment.html

---

From: gsexton at mhsoftware.com (George Sexton)
Date: Mon Feb 19 20:20:35 2007

> RRULE:FREQ=MONTHLY;BYMONTHDAY=15,30
No. This would include the 15th of February only. Why do you think it 
would not apply to February? The FREQ is monthly, and February is a 
month too.
> RRULE:FREQ=MONTHLY;BYMONTHDAY=1,-1
No, this would include the 1st of February, and the  28th (or 29th for 
leap years).
> RRULE:FREQ=MONTHLY;BYMONTHDAY=15,30
Agan, this is the 15th of February only.
> RRULE:FREQ=DAILY;BYMONTHDAY=15,30
This also would include only the 15th of February.
>  
>  
> I don't find the above particularly obvious, so in case it helps, my 
> thinking is that you use DTSTART and FREQ to create the initial 
> recurrence set, and then refine/expand it using the BYXXX rules.  As 
> there is no 30th of Feb, the initial recurrence set contains no dates 
> in February, and hence we have no date in february to expand or refine 
> to create additional dates in february in the context of a monthly rule.
>  
> If I am right, and you also consider the above not particularly 
> obvious, perhaps it worth refining this paragraph in RFC2445 to spell 
> out the algorithm.  I suggest we move the "invalid date" paragraph 
> down one, and then:
>  
> ------------------------------------------------------------------------
>
> _______________________________________________
> Ietf-calsify mailing list
> [email-masked]
> http://lists.osafoundation.org/mailman/listinfo/ietf-calsify
>   

-- 
George Sexton
MH Software, Inc.
Voice: +1 303 438 9585
URL:   http://www.mhsoftware.com/

---

From: cyrus at daboo.name (Cyrus Daboo)
Date: Mon Feb 19 20:44:08 2007

Hi George,

--On February 19, 2007 9:19:33 PM -0700 George Sexton 
<[email-masked]> wrote:

> would not apply to February? The FREQ is monthly, and February is a month
> too.

I think I agree with George on this - 15th February should be included. 
That is in spite of the fact that an implementation I wrote does not do 
that - oh well :-(

-- 
Cyrus Daboo

---

From: reinhold at kainhofer.com (Reinhold Kainhofer)
Date: Mon Feb 19 22:39:13 2007

Am Dienstag, 20. Februar 2007 schrieb Nigel Swinson:
> thinking is that you use DTSTART and FREQ to create the initial recurrence
> set, and then refine/expand it using the BYXXX rules.

Isn't the RFC saying the exact opposite? First you apply the FREQ and the BY* 
rule parts, and only what's missing after that is taken from DTSTART. So if 
no BYDAY was given in your examples, then the event would not occur in 
february. But any BYDAY rule part overrides the 30th and the event will occur 
in february. 
"Information, not contained in the rule, necessary to determine the various 
recurrence instance start time and dates are derived from the Start Time 
(DTSTART) entry attribute."

Cheers,
Reinhold

- -- 
- ------------------------------------------------------------------
Reinhold Kainhofer, Vienna University of Technology, Austria
email: [email-masked], http://reinhold.kainhofer.com/
 * Financial and Actuarial Mathematics, TU Wien, http://www.fam.tuwien.ac.at/
 * K Desktop Environment, http://www.kde.org, KOrganizer maintainer
 * Chorvereinigung "Jung-Wien", http://www.jung-wien.at/

---

From: Nigel.Swinson at rockliffe.com (Nigel Swinson)
Date: Wed Feb 21 09:07:19 2007

> (DTSTART) entry attribute."

I could see this going either way, hence I thought it worthy of a mail.  Judging by Cyrus' response, I'm not the first to stumble on this subtlety.  

I guess the problem is you have to have some way of representing the recurrence set as you go along.  Start with an empty set, then apply FREQ and INTERVAL from DTSTART, then the BYX parts in the specified order.  It seems obvious to use Date/DateTime objects to represent these dates where you have a valid recurrence set after each step of processing.  But doing this means you have to set the year, month, day, (hour, minute, second) to something, or else carry about some kind of mask to say what does, and does not have valid data.

Given that iCalender tells us that DTSTART is to be the first instance, and we are to use DTSTART to get information not already available in the BYX rule parts, it seems to create a much simpler, less error prone algorithm to just take DTSTART + n*FREQ to create a set of dates, filtering out those that can't exist, and apply the BYX rule parts.  Then at each stage in the processing, you have a valid set of dates.

But doing it this way means that as in my example, a DTSTART of Jan 30th and a FREQ of MONTHLY would automatically eliminate any recurrences in Feb.  I can't say I'm too sad about that, as the rule can be rewritten as a DAILY instead to ensure it doesn't exclude February.

So I'd like to push for permitting this kind of algorithm.

Even if you are not persuaded, and I suspect you are not, then I still think it would be worth spelling out perhaps in numbered steps an algorithm that will meet the philosophy of the standard.  Trying to extract this from several paragraphs of prose is pretty tricky and is only going to result in interoperability problems.  If people agree to this in principle, then I'd be happy to have a go at some suggested text?

Nigel

---

From: mikesamuel at gmail.com (Mike Samuel)
Date: Wed Feb 21 12:56:44 2007

> Given that iCalender tells us that DTSTART is to be the first instance, and we are to use DTSTART to get information not already available in the BYX rule parts, it seems to create a much simpler,…

I think if you define
  T0 === the greatest date that starts a period that is <= DTSTART
and instead of DTSTART + n * FREQ you use
  T0 + n * INTERVAL * FREQ
you can make this approach work.

You just have to filter out from the first period any that are < DTSTART.

Either way, your algorithm doesn't require that the entire set be
discarded if a single date is nonsensical.

See http://google-rfc-2445.googlecode.com/svn/trunk/src/com/google/ical/iter/RRuleIteratorImpl.java
for an alternate algorithm which uses separate producers of years,
months, and days.  Each by*** rule can be treated as either a producer
or a filter which allows some degree of flexibility in choosing the
combination of producers/filters that needs to do the least work.

---

From: mikesamuel at gmail.com (Mike Samuel)
Date: Wed Feb 21 19:11:35 2007

My objection to your interpretation of
RRULE:FREQ=MONTHLY;BYMONTHDAY=15,30 is that it does not have the
property that

  for every RRULE r (with no count) and a DTSTART d1, if I pick a date
d2 from the series (r, d1)
  then the series (r, d2) should be a tail of (r, d1)

On 19/02/07, Nigel Swinson <[email-masked]> wrote:
> set, and then refine/expand it using the BYXXX rules.  As there is no 30th
> of Feb, the initial recurrence set contains no dates in February, and hence
> we have no date in february to expand or refine to create additional dates
> in february in the context of a monthly rule.
>
> If I am right, and you also consider the above not particularly obvious,
> perhaps it worth refining this paragraph in RFC2445 to spell out the
> algorithm.  I suggest we move the "invalid date" paragraph down one, and
> then:
>

---

From: mikesamuel at gmail.com (Mike Samuel)
Date: Wed Feb 21 19:17:21 2007

Ack, sorry, rules with a BYSETPOS with non-negative indices don't have
this property either but I think that's a small enough set of rules
that the principal is one that shouldn't be violated needlessly.

mike