views:

764

answers:

4

Hi,

I'm using Google's RFC2445 implementation (http://code.google.com/p/google-rfc-2445/) for recurrence rules. If I define a MONTHLY recurrence starting on the 30th of January, months with less than 30 days (i.e., February) will be totally skipped. So the Google API would return 30th Jan, 30th March, 30th April, etc. Not good. I would expect it to return: 30th Jan, 28th Feb, 30th March, 30th April.

Similarly, if I picked a start date of the 31st of January, then any months with less than 31 days would be skipped.

This may be correct as per the RFC2445 spec or may be a bug. What do you think?

My main question is, is there any way to define a rule which says "recur on the 30th of every month; or the last day of the month if the 30th doesn't exist". I do not believe there is. Any suggestions?

Thanks in advance.

Regards, Cormac

A: 

Well, looking at RFC 2445 itself it definitely seems that the behavior you're seeing is correct:

If BYxxx rule part values are found which are beyond the available scope (ie, BYMONTHDAY=30 in February), they are simply ignored.

The only solution I can think of is to use multiple recurrence rules, i.e. one for the 30th of every month and another for the last day in February.

David Zaslavsky
A: 

It looks like you're right about the RFC skipping those dates. If your DTSTART is January 31, and you don't specify a BYMONTHDAY in your recurrence rule (or if BYMONTHDAY is on the 31st), then it'll simply ignore that rule in months where there is no such day:

If BYxxx rule part values are found which are beyond the available scope (ie, BYMONTHDAY=30 in February), they are simply ignored.

However, you should be able to specify -1 for BYMONTHDAY and have it use the last day of the month, whatever it may happen to be.

The BYMONTHDAY rule part specifies a COMMA character (ASCII decimal 44) separated list of days of the month. Valid values are 1 to 31 or -31 to -1. For example, -10 represents the tenth to the last day of the month.

Adam Bellaire
The negative numbers almost work; the questioner wants -2 on months with 31 days, -1 on months with 30 (or 29 or 28) days. Much closer...
Jonathan Leffler
This is true, I didn't think it was possible, but he found the BYSETPOS on his own, which does exactly what he wants.
Adam Bellaire
A: 

Hi,

If BYxxx rule part values are found which are beyond the available scope (ie, BYMONTHDAY=30 in February), they are simply ignored.

I'm not using any of the BYxxx rules though this isn't the case here.

The rule I am using is simply RRULE:FREQ=MONTHLY.

BYMONTHDAY=-1 would be fine if that is what was required, but I'm looking for a rule that exactly defines "recur on the 30th of every month; or the last day of the month if the 30th doesn't exist".

Thanks for the comments.

Cheers, Cormac

Cormac Redmond
The information here should be added to your question and this 'pseudo-answer' should be deleted.
Jonathan Leffler
+3  A: 

The answer is: FREQ=MONTHLY;BYMONTHDAY=28,29,30;BYSETPOS=-1 which translates to "recur on the 30th of every month; or the last day of the month if the 30th doesn't exist".

Cormac Redmond
Can you explain why the BYMONTHDAY=28,29,30 translates to 30th of month, and not 28th and 29th and 30th?
Jonathan Leffler
It's because of the BYSETPOS syntax. A more accurate translation would be "recur on the last (-1) POSITION from the SET 28, 29, 30 which exists for the given month." So if the 30th doesn't exist, the last valid item in the set is 29. If that doesn't exist, it's 28. Nice find, @Cormac Redmond!
Adam Bellaire