0

I am building something that takes an icalendar event and calculate all occurrences of a repeating event.

I have discovered a problem which returns me a few YEARLY events every month. Those event has a yearly frequency but only have bymonthday without bymonth value.

Is this specified in the RFC-5545 or is this just a bug from my calendar tool. (PS: This is actually in my Google Calendar and this event displays correctly there)

BEGIN:VEVENT
DTSTART;VALUE=DATE:20110814
DTEND;VALUE=DATE:20110815
RRULE:FREQ=YEARLY;BYMONTHDAY=14
DTSTAMP:20170328T223152Z 
UID:388B4AE8602346DAA7BD9C1906FC390200000000000000000000000000000000
CREATED:20110610T073603Z
DESCRIPTION:
LAST-MODIFIED:20160811T230008Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Some BDAY
TRANSP:OPAQUE
CATEGORIES:http://schemas.google.com/g/2005#event
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-P1DT15H
ACKNOWLEDGED:20160811T230006Z
ATTACH;VALUE=URI:Basso
UID:26C6C0F7-8B77-4E20-8EFD-E82A614B0751
X-WR-ALARMUID:26C6C0F7-8B77-4E20-8EFD-E82A614B0751
END:VALARM
BEGIN:VALARM
ACTION:NONE
TRIGGER;VALUE=DATE-TIME:19760401T005545Z
END:VALARM
END:VEVENT
maxi C
  • 142
  • 1
  • 13

2 Answers2

1

In the RFC 5545 - page 44 to be exact - the BYMONTHDAY is specified to expand a yearly rule, i.e. to generate more results that only 1 per year.

Furthermore on the next page it gives an example of how a rrule must be evaluated:

DTSTART;TZID=America/New_York:19970105T083000
  RRULE:FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;
  BYMINUTE=30

First, the "INTERVAL=2" would be applied to "FREQ=YEARLY" to arrive at "every other year". Then, "BYMONTH=1" would be applied to arrive at "every January, every other year". Then, "BYDAY=SU" would be applied to arrive at "every Sunday in January, every other year". Then, "BYHOUR=8,9" would be applied to arrive at "every Sunday in January at 8 AM and 9 AM, every other year". Then, "BYMINUTE=30" would be applied to arrive at "every Sunday in January at 8:30 AM and 9:30 AM, every other year".

As you can see, even if FREQ is YEARLY, the rule will return "every Sunday in January at 8AM and 9AM, every other year", i.e. much more than 1 occurrence every two year. That is in a nutshell the concept of expanding the behavior of FREQ.

Now applying to this rule:

RRULE:FREQ=YEARLY;BYMONTHDAY=14

It means "every 14th of the month, every year". So you will get 12 occurrences per year.

Edit: That being said, after re-reading the RFC, the definition of BYMONTHDAY is:

The BYMONTHDAY rule part specifies a COMMA-separated list of days of the month.

This could be interpreted as "list of days of the month" as in "only the month specified by DTSTART property". However this interpretation does not make sense with other values of FREQ (MONTHLY, DAILY, etc.), so that would be a special case only for FREQ=YEARLY and BYMONTH is missing... Personally I do not believe it is correct, but I must admit the RFC is slightly ambiguous.

Unfortunately there isn't any example of BYMONTHDAY with FREQ=YEARLY without BYMONTH, so there is no clear definite answer

Conclusion: To avoid any problem you should add a BYMONTH if you want only "the 14th of a given month".

Answer to your comment

The rule "FREQ=MONTHLY;BYMONTHDAY=14" indeed produces the same result. The differences would appear with INTERVAL greater than 1, or other BYxxx.

Community
  • 1
  • 1
rlanvin
  • 6,057
  • 2
  • 18
  • 24
  • Is this rule RRULE:FREQ=YEARLY;BYMONTHDAY=14 different from RRULE:FREQ=MONTHLY;BYMONTHDAY=14? I have setup this event 14th Auguest day to occur exactly once per year in Google calendar, does that mean Google calendar has stored this event with a wrong RRULE? – maxi C Mar 30 '17 at 00:31
  • @maxiC I have edited and completed my answer. I can't say for certain Google Calendar is *wrong*, but it is definitely very ambiguous. – rlanvin Mar 30 '17 at 08:53
  • ok, thanks for your great help! The difference between both with INTERVAL specified definitely does make sense. – maxi C Apr 01 '17 at 03:16
0

IMO FREQ=YEARLY;BYMONTHDAY=14 should generate only a single event on the 14th of August every year.

RFC 5545, page 42 says:

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".

So in your case the rule doesn't specify the month, hence it's inherited from the start date. In your case that's August.

Check out the instances our library generates for this event: FREQ=YEARLY;BYMONTHDAY=14

Community
  • 1
  • 1
Marten
  • 3,802
  • 1
  • 17
  • 26