Cron tools › Convert
Cron to iCal RRULE
Put a cron job on a calendar. The converter writes the RRULE (or two, when cron's day fields combine with OR),
builds a valid .ics file around it, and proves it by parsing the rule back and expanding it from its DTSTART —
the occurrences must be the cron line's runs. A second download lists the next runs as plain events for calendars that
struggle with complex rules.
RRULE
Next runs as single events
Each run becomes its own event with a UTC start time, so every calendar shows the right moment. Nothing repeats, so re-export when the list runs out.
Try one
How to turn a cron schedule into a calendar event
- Paste the cron expression. Quartz, Spring and AWS expressions work too, including
L,#andnL. - Choose Floating to show the event at the same clock time wherever the calendar is, or UTC to pin it to an instant.
- Copy the RRULE into your own code, or download the
.icsand import it into a calendar. - For a calendar that mishandles rules, pick the zone the job runs in and download the next runs as single events.
How cron maps to RRULE
| Cron | RRULE | Why |
|---|---|---|
| 0 9 * * 1-5 | FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR;BYHOUR=9;BYMINUTE=0 | with DAILY, BYDAY limits the days and BYHOUR/BYMINUTE expand the times |
| 0 0 1,15 * * | FREQ=DAILY;BYMONTHDAY=1,15;BYHOUR=0;BYMINUTE=0 | BYMONTHDAY also limits |
| */20 * * * * | FREQ=HOURLY;BYMINUTE=0,20,40 | minutes listed, not INTERVAL (see below) |
| 0 0 12 ? * 3#2 (Quartz) | FREQ=MONTHLY;BYDAY=2TU;BYHOUR=12;BYMINUTE=0 | numbered BYDAY needs MONTHLY or YEARLY |
| 6L (Quartz dow) | BYDAY=-1FR | last Friday of the month |
| L (Quartz dom) | BYMONTHDAY=-1 | BYMONTHDAY takes -31 to -1 from the end |
| LW (Quartz dom) | FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1 | last weekday; one event per time of day |
| 0 0 1 * 1 | two events | cron ORs the day fields; an RRULE's parts all have to match |
Why */7 is not INTERVAL=7
It is tempting to write cron's */7 as FREQ=MINUTELY;INTERVAL=7. They are different schedules. Cron's step
restarts every hour — :00, :07 … :56, then :00 again, four minutes later — while INTERVAL counts from DTSTART and keeps going
across the hour: :00, :07 … :56, 1:03, 1:10. This converter always lists the values in BYMINUTE / BYHOUR, which match cron
exactly, and the check would catch the difference if it did not.
Floating time or UTC?
Floating (no zone) means "09:00 on whatever clock the calendar uses". It suits a personal reminder, and it follows
daylight saving automatically. A colleague in another zone sees it at their 09:00, though. UTC pins every
occurrence to one instant for everyone, but the cron fields are then read as UTC, so a job meant for 09:00 local time drifts by
an hour when the clocks change. A TZID would be the third option; it needs a VTIMEZONE definition in the
same file, which this page does not generate, so it never writes one.
FAQ
Why did I get two events?
Because the cron line restricts both day-of-month and day-of-week, which in cron means "either". Every part of one RRULE has to match, and RFC 5545 says RRULE SHOULD NOT occur more than once in an event, so the file holds one event per half. Together they cover exactly the cron runs.
Is the .ics file valid?
It uses CRLF line endings, folds lines longer than 75 octets, escapes commas, semicolons and backslashes in text, and gives every event a UID, DTSTAMP and DTSTART that is itself the first occurrence of the rule.
What cannot be converted?
Quartz's "nearest weekday" W has no RRULE form, a year list or step cannot be written (a single range of years
becomes DTSTART plus UNTIL), and @reboot has no time at all. The "next runs" download still works for all of them.
What happens to a run in a skipped DST hour?
RFC 5545 says an occurrence at a local time that does not exist must be ignored. Linux cron (cronie) instead runs a fixed-time job right after the clock jumps, so on that one day a floating calendar entry and the real job disagree.