9

How would you specify a rrule for an event on the 31st day of the month (or 30th, or 29th) that recurs every month, where if the month doesn't have enough days it picks the closest (i.e. for February it would pick the 28th or 29th, for April it would pick the 30th)?

Technically I'm using the rrule javascript library if that's relevant.

To add context, I have a form where the user can specify a start date an recurrence (yearly, monthly, weekly, daily), like for a bill. If a bill is usually due on the 30th then in February it will be due the 28th (or 29th).

arolson101
  • 1,473
  • 15
  • 29

2 Answers2

14

There is a new extension to RRULE called RSCALE to cover that case. Unfortunately it's not widely supported yet. Not sure about the Javascript rrule library you're using, but you should open an issue if it's not the case.

Using the RSCALE extension your RRULE would look like so:

FREQ=MONTHLY;RSCALE=GREGORIAN;BYMONTHDAY=31;SKIP=BACKWARD

Events having this RRULE recur on every 31st each month, unless that day doesn't exist in which case SKIP=BACKWARD says "use the previous valid day".

Edit

I've just been made aware of another way to express this without RSCALE:

31st each month with a fallback to the last valid day in that month:

FREQ=MONTHLY;BYMONTHDAY=28,29,30,31;BYSETPOS=-1

30th each month with a fall back to the 28th or 29th (in leap years) in February

FREQ=MONTHLY;BYMONTHDAY=28,29,30;BYSETPOS=-1

29th each month with a fall back to the 28th in February in non-leap years

FREQ=MONTHLY;BYMONTHDAY=28,29;BYSETPOS=-1

However, as one can see this is clearly more intuitive with RSCALE.

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

The simplest RRULE to get "the last day of the month", regardless of whether it falls on the 28th, 29th, 30th, or 31st would be:

FREQ=MONTHLY;BYMONTHDAY=-1

Your query sounds like that's what you're after.

I don't know if this is supported by the rrule javascript library you mention, however.

tgi007
  • 131
  • 3
  • This is not right. An additional `BYMONTHDAY=28,29,30,31` is needed – Julius Š. Apr 12 '18 at 10:54
  • @JuliusŠ. Not sure what you mean by "_an additional_", as [RFC 2445](http://www.ietf.org/rfc/rfc2445.txt) section 4.3.10 "Recurrence Rule" explicitly states that keywords such as BYMONTHDAY "_are optional, but MUST NOT occur more than once_". If, instead, you meant `BYMONTHDAY=-1,28,29,30,31` then the result will be _all_ days numbered 28 through the end of the month. – tgi007 Jul 25 '18 at 03:55
  • 2
    The rrule javascript library appears to have a [demo](https://jakubroztocil.github.io/rrule) where possible solutions can be tested. `FREQ=MONTHLY;BYMONTHDAY=-1` produces the expected result when entered under _RRULE String_ as input. – tgi007 Jul 25 '18 at 04:07
  • This is the better answer. From RFC2445: "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." – Dan Luba Aug 15 '22 at 09:07
  • @DanLuba it's not what the OP asked for. `BYMONTHDAY=-1` always recurs on the last day of the month. If you want your event to recur on the 30th of the month, falling back to the last day of February, this approach won't work. – Marten Dec 19 '22 at 20:25
  • @Marten I won't quibble, but I'm not convinced. – Dan Luba Dec 20 '22 at 00:33
  • Why is this not the accepted answer? – braaterAfrikaaner Dec 20 '22 at 18:48
  • @Marten actually, this is precisely what OP asked for, the 31st or closest day if 31st doesn't exist. This is equivalent to asking for the last day in a month. You are asking a different question. – braaterAfrikaaner Dec 20 '22 at 18:50
  • Maybe it's not the accepted answer because it didn't solve the OP's problem. The OP stated `an event on the 31st day of the month (or 30th, or 29th) that recurs every month …`. That expands to `an event on the 31st day that recurs every month or an event on the 30th day that recurs every month or an event on the 29th that recurs every month …`. That's a reasonable use case and the solution is not necessarily obvious. I agree that this answer is the best one in case of `31st or closest`. – Marten Dec 20 '22 at 20:41