I am currently struggling with an interpretation detail of RFC 5545. Section 3.3.10 states that essentially, all BYxxx
fields show an expanding behavior, except for BYDAY
, which has specific rules depending on which BYxxx
fields are actually present.
However, it is unclear to me what exactly is supposed to happen for an RRULE
that specifies more than one of {BYMONTH
, BYWEEKNO
, BYYEARDAY
}. In my opinion the table in Section 3.3.10 allows for the interpretation that I have to expand every rule part separately, that is, to build the union of the three sets resulting from
BYMONTH
, BYMONTHDAY
etc.BYWEEKNO
BYYEARDAY
all the while honoring Note 2 that explains the BYDAY
behavior. The result can be somewhat counter-intuitive (and of course it is fairly unlikely that users would specify such rules). But there is at least one implementation out there that claims to do it this way:
For the
YEARLY
frequency, theBYMONTH
,BYWEEKNO
, andBYYEARDAY
rules are expanded separately from each other if specified.
Other implementations, such as http://recurrence-expansion-service.appspot.com/ or Google Calendar, appear to use a limiting strategy if more than one of the rule parts are present:
BYMONTH
/BYMONTHDAY
BYWEEKNO
and BYYEARDAY
effeectively creating an intersection rather than a union. That approach seems somewhat consistent with the application order for the rule parts stipulated by Section 3.3.10:
If multiple
BYxxx
rule parts are specified, then after evaluating the specifiedFREQ
andINTERVAL
rule parts, theBYxxx
rule parts are applied to the current set of evaluated occurrences in the following order:BYMONTH
,BYWEEKNO
,BYYEARDAY
,BYMONTHDAY
,BYDAY
,BYHOUR
,BYMINUTE
,BYSECOND
andBYSETPOS
; thenCOUNT
andUNTIL
are evaluated.
However, interpreting this to mean that the rule parts are limiting rather than expanding appears to me to be in direct contradiction of the expand/limit table shown on page 44 of the standard.
My question thus is:
Does RFC5545 actually unambiguously specify how the simultaneous presence of more than one of BYMONTH
, BYWEEKNO
and BYYEARDAY
is to be interpreted? If so, where does it state it? And if the standard is actually unclear in this regard, is there a “de-facto standard” preferred way of dealing with this situation?
Does RFC5545 actually unambiguously specify how the simultaneous presence of more than one of BYMONTH, BYWEEKNO and BYYEARDAY is to be interpreted?
Well yes, in the excerpt you quoted in your question: they are applied to the current set of evaluated occurrences in order.
The term current set of evaluated occurrences is the key part of the sentence. For example let's take a rule with BYMONTH and BYYEARDAY.
The expand/limit table is irrelevant in this case. The RFC states very clearly:
"The table below summarizes the dependency of BYxxx rule part expand or limit behavior on the FREQ rule part value."
The table does not summarizes the behavior of BYxxx rule part on other BYxxx rule parts.
Therefore it is unambiguously an intersection. Think about it that way: if the result was a union, there would be no way to write rules such as "every day of the 5th week of the year that are in February" (FREQ=YEARLY;BYWEEKNO=5;BYMONTH=2
).
To achieve a union, the RFC defines a recurrence set, which is simply combining multiple RRULE, RDATE and EXDATE (though for some reason the RFC states that RRULE should not appear more than once).
And if the standard is actually unclear in this regard, is there a “de-facto standard” preferred way of dealing with this situation?
I am the maintainer of php-rrule which is a port of Python dateutil and this is how both version handle this situation. As far as I remember, Javascript and Ruby libraries also work this way. I don't know about every other libraries that is out there, but the RFC is quite clear anyway, as I hope I have demonstrated above.
The Note 2 of the table can be indeed quite confusing, so here is a little clarification. BYDAY
is special because it has 2 syntaxes: the simple one with the name of the day (e.g. MO
, TU
and so on) and the "complicated" one with the name of the day and the position in the set. For example 1MO
means "the first Monday" and -1MO
"the last Monday". However the question is "the first/last Monday of what?".
BYDAY=1MO,2MO
, it is "the first and the second Monday of the year", when using MONTHLY it is "the first and the second Monday of the month" and so on, this is pretty straightforward.BYMONTH=2,3
for example then the rule actually means "every February and March" so the question is: should you get every first and second Monday of February and March (expand), or every first and second Monday of the year that occur in February and March - i.e. empty set, since both are in January (limit). The answer is to do a "special expand" by actually treating it as a "MONTHLY" frequency (even if it is YEARLY) and therefore the meaning of BYDAY=1MO,2MO
changes to "every first and second Monday of February AND every first and second Monday of March`.Quote relevant part of the RFC
The numeric value in a BYDAY rule part with the FREQ rule part set to YEARLY corresponds to an offset within the month when the BYMONTH rule part is present, and corresponds to an offset within the year when the BYWEEKNO or BYMONTH rule parts are present.
To be perfectly honest I'm not sure why there is this special case for BYDAY, but in any case it's quite clear how it should behave.