cronkit.org
Cron expressions, explained and converted — in your browser

Cron tools › Convert

Cron to systemd timer

OnCalendar= · .timer + .service units · checked against cron

Paste a crontab schedule and get the OnCalendar= line, a .timer and a .service unit, and the commands to enable them. The OnCalendar expression is expanded by the same evaluator as the OnCalendar tester and compared with the cron line's next 500 runs.

OnCalendar

Unit files

Try one

How to replace a cron job with a systemd timer

  1. Paste the schedule part of the crontab line and fill in a unit name and the command.
  2. Save the two units as /etc/systemd/system/name.timer and name.service — the Download buttons give you the files.
  3. Run sudo systemctl daemon-reload, then sudo systemctl enable --now name.timer.
  4. Confirm the schedule with systemd-analyze calendar '…' and systemctl list-timers.
  5. Remove the old line from the crontab, or the job will run twice.

How cron fields map to OnCalendar

CronOnCalendarNote
30 9 * * **-*-* 09:30:00date as Y-M-D, time as H:M:S
0 9 * * 1-5Mon..Fri *-*-* 09:00:00weekday names, ranges with ..
*/15 * * * **-*-* *:00/15:00repetition /n from a start value
0 0 1,15 * **-*-01,15 00:00:00lists with ,
0 0 1 */3 **-01/3-01 00:00:00every third month from January
0 0 L * ? (Quartz)*-*~01 00:00:00~ counts from the end of the month
0 0 1 * 1two OnCalendar= linescron ORs the day fields; systemd ANDs weekday and date
@daily*-*-* 00:00:00systemd's own daily means the same

Quartz, Spring and AWS input works too: seconds carry over (systemd has a seconds field), an nth weekday such as 2#1 becomes Mon *-*-01..07, and a last weekday such as 6L becomes Fri *-*~07/1. "Nearest weekday" (W, LW) has no OnCalendar form and is refused with an explanation.

The timer settings that matter

FAQ

Why did I get two OnCalendar= lines?

Because the cron line sets both day fields. Cron then runs when either matches, while the weekday and date in one OnCalendar expression must both match. One line per half, in the same timer, gives the cron behaviour back.

Does the timer use my local time or UTC?

Without a zone in the expression, the machine's local time — the same as cron. Pick a zone in the tool and it is appended to each OnCalendar= line (for example Mon..Fri *-*-* 09:00:00 Europe/Berlin).

Why is my command wrapped in /bin/sh -c?

ExecStart= runs a program directly, not through a shell, so pipes, redirects, && and variables would be passed as literal arguments. The converter wraps such commands in /bin/sh -c "…" and doubles % and $, which unit files treat as specifiers.

How do I see when the timer will fire?

systemctl list-timers shows the next elapse of every active timer, and systemd-analyze calendar 'Mon..Fri *-*-* 09:00:00' prints the normalized form and the next elapse of an expression. The OnCalendar tester does the same in the browser.