Monthly dates starting on January 31
A January 31 monthly schedule needs an explicit missing-date rule because February has no 31st. With month-end selected, the first four dates are January 31, February 28, March 31 and April 30 in 2026; with skip selected, February and every other month without a 31st are omitted.
The calendar
One standards-based all-day VEVENT per row, with exclusive next-day DTEND values and stable event identifiers.
Every date in the schedule
| 1 | 2026-01-31 | Saturday | 0 | Anchor date |
| 2 | 2026-02-28 | Saturday | 28 | Moved to month end |
| 3 | 2026-03-31 | Tuesday | 59 | Exact anchor day |
| 4 | 2026-04-30 | Thursday | 89 | Moved to month end |
| 5 | 2026-05-31 | Sunday | 120 | Exact anchor day |
| 6 | 2026-06-30 | Tuesday | 150 | Moved to month end |
| 7 | 2026-07-31 | Friday | 181 | Exact anchor day |
| 8 | 2026-08-31 | Monday | 212 | Exact anchor day |
| 9 | 2026-09-30 | Wednesday | 242 | Moved to month end |
| 10 | 2026-10-31 | Saturday | 273 | Exact anchor day |
| 11 | 2026-11-30 | Monday | 303 | Moved to month end |
| 12 | 2026-12-31 | Thursday | 334 | Exact anchor day |
Each candidate is derived from the original day 31, so February 28 does not make March recur on the 28th.
Month-end mode reports every shortened occurrence in the adjustment column.
Skip mode keeps searching candidate months until it has produced the requested number of actual dates.
How it works
How it is done
- Parse the first date as a Gregorian calendar anchor, then bound the interval and requested occurrence count before allocating the schedule.
- For days and weeks, add a fixed number of UTC calendar days. For months and years, derive every candidate from the original year, month and day rather than from the previous result.
- If a candidate month lacks the anchor day, either use its final day or omit that candidate, exactly as selected. Continue until the requested number of actual dates has been produced.
- Write the rows as separate RFC 5545 all-day VEVENT components. DTSTART is the date itself, DTEND is the following date because an all-day end is exclusive, and every content line is folded at 75 UTF-8 octets.
What it assumes
- The calendar is Gregorian and date-only. There is no time of day, time zone, daylight-saving transition or reminder to infer.
- The first date counts as occurrence one. Twelve dates therefore contain eleven intervals, not twelve.
- Month-end mode never changes the anchor. January 31 can become February 28 and then return to March 31 because each candidate is derived from the original day 31.
- Skip mode skips a missing candidate, not an interval. It continues through later candidate months or years until the requested number of real dates exists.
- Calendar years beyond 9999 cannot be represented by RFC 5545's four-digit DATE value and are not emitted.
Common questions
Why is adding one month repeatedly different from using an anchor day?
If February 28 becomes the input to the next addition, every later month can remain on the 28th. Deriving each date from the original January 31 anchor prevents that permanent drift.
What happens to February 29 on a yearly schedule?
Month-end mode uses February 28 in non-leap years and returns to February 29 in leap years. Skip mode includes only years in which February 29 exists.
Sources
The full method, worked example and every assumption behind this figure are on Recurring Date Schedule Maker.