Subject: Re: Can we fix BYSETPOS?

From: [email-masked]
Date: Wed, 20 Jun 2001 11:56:11 -0400

Jonathan replied with:
>> >        RECUR:FREQ=WEEKLY;BYMONTH=4;BYSETPOS=1
[Snip, snip]
>> W/o the BYSETPOS=1, this rule says that the entry repeats every week in 

>> April.  If I had a DTSTART;TZID=US-Eastern:20010406T090000 w/this rule 
then the repeat set would be:
>> 
>> (09:00:00 EDT) 06-Apr-2001, 13-Apr-2001, 20-Apr-2001, 27-Apr-2001
>> (09:00:00 EDT) 05-Apr-2002, 12-Apr-2002, 19-Apr-2002, 26-Apr-2002
>> ...
>> 
>> However w/the BYSETPOS=1 the resulting repeat set becomes:
>> 
>> (09:00:00 EDT) 06-Apr-2001
>> (09:00:00 EDT) 05-Apr-2002
>> ...
>
>Why?
>
>Why is the "set," for this rule, "all the events within a year" (or is it
>"within a month"), rather than, say, "within a week" (FREQ) or "within
>twenty-eight years" (least-common-multiple of BYMONTH and WEEKLY)?

If you follow the decoding guidelines in Section 4.3.10 (p. 44 generally) 
then you decode the RRULE in the following way:

1: There is an implicit "INTERVAL=1" defined so this rule starts as "Every 
week" (or "Every week in the year forever" if you want a more verbose 
description")
2: "BYMONTH=4" refines it down to "Every week in April (forever)"
3: "BYSETPOS=1" refines it to "The first instance of the set of 
dates("Every week in April (forever)")"

So if you inherit the time value from the DTSTART (since we have no time 
only BYxxx subcomponents in this case) and then you start rolling out the 
set based on the initial DTSTART date/time value.

So if we had stopped @ step #2 (ie: no "BYSETPOS") then you get the first 
set of dates/times I listed.  If we apply step #3 (ie: a "BYSETPOS") then 
we get the second set of dates/time I listed.

>Can you write a pseudo-code algorithm which, for any combination of FREQ,
>INTERVAL, and any BY* rules except BYSETPOS, tells me which event
>recurrences should be marked as beginning a "set"?

The text on the bottom of p. 44 of 2445 lays it out fairly well in plain 
english:

   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.

but it includes BYSETPOS near the end of the ordering for obvious reasons. 
 COUNT / UNTIL are used as the 'until()' clause of your repeat/until loop 
(or your favorite do/while or other looping style of control). 

Bruce
===========================================================================
Bruce Kahn                                INet: [email-masked]
Iris Associates                          Phone: 978.392.5335
Westford, MA, USA 01886                    FAX: and nothing but the FAX...
Standard disclaimers apply, even where prohibited by law...

---

From: Jonathan Lennox <[email-masked]>
Date: Wed, 20 Jun 2001 14:02:49 -0400 (EDT)

On Wednesday, June 20 2001, "[email-masked]" wrote to "Jonathan Lennox, Eric Busboom, [email-masked]" saying:

[We're discussing
       RRULE:DTSTART;TZID=US-Eastern:20010406T090000
       RECUR:FREQ=WEEKLY;BYMONTH=4;BYSETPOS=1
]

> dates("Every week in April (forever)")"

Step 3 is the step I don't get, and it's where the definition of "set" is
crucial.

Clearly, "the set of dates consisting of the first instance of the set of
dates 'Every week in April, forever'" has exactly one member - one day in
April.

Similarly, "the set of dates consisting of the last instance of the set of
dates 'Every week in April, forever'" is ill-defined, as there is no such
last instance -- the set continues (as it says) forever.

So you're implicitly assuming some other algorithm for determining the
meaning of BYSETPOS, presumably derived from whatever algorithm you're using
to enumerate infinite sets.

If I decided to use an algorithm of "expand the set so that all events are a
constant-time offset from n * constant-period + DTSTART", my sets for the
above rule would be twenty-eight years in length (ignoring the Gregorian
correction and any year-dependent changes in time zone rules).

If I decided to use an algorithm of "for any given instance of n * FREQ +
DTSTART, check to make sure it complies with all the contracting rules and
INTERVAL, then apply the expanding rules", my set would be one week in
length (and would have only a single member).

Other than for BYSETPOS, both of these are reasonable implementation
strategies for recurrence rules, I think.  I have to admit, though, I don't
see any implementation strategy for which "one year" is a natural resulting
set for this rule.

The standardized meaning Eric and I came up with was that the enclosing set
was the unit of time indicated by FREQ.  This is a natural fit with the
second algorithm I said above, and is easy to explain and to understand.
However, this clearly isn't what you're doing.  So I don't understand what
you *are* doing.

Can you explain it?  I.e., do you agree with the following general
statements, and can you answer the question, in the model of recurrence rules
you're using?

       Given a recurrence rule with a BYSETPOS rule, we have a period of
       time P (possibly with an irregular length, such as a month) such that
       BYSETPOS=1 indicates the first event following n * P + DTSTART for
       integer n >= 0, and BYSETPOS=-1 indicates the last event preceding n *
       P + DTSTART for integer n >= 1.

       P is independent of INTERVAL, COUNT, UNTIL, and expanding BY* rules.
       It depends only on FREQ and contracting BY* rules.

       Given a recurrence rule with a specified FREQ and some number of
       specified contracting BY* rules, how can you determine P?

-- 
Jonathan Lennox
[email-masked]