cron to systemd timer converter
Paste a crontab line, get a working .timer and .service pair plus the command to enable it.
Last updated
In short: To replace a cron job with a systemd timer, write two files: name.service runs the command, name.timer holds the schedule as an OnCalendar= line such as Mon..Fri *-*-* 03:30:00 (cron 30 3 * * 1-5). Put them in ~/.config/systemd/user/ and run systemctl --user daemon-reload && systemctl --user enable --now name.timer. This converter writes both files, shows the next 5 runs and handles cron's day-of-month OR weekday rule.
Your input never leaves your browser. Everything is calculated on your device; nothing you type is sent to a server.
How does the cron to systemd timer converter work?
A cron line packs the schedule and the command into one row: five time fields (minute, hour, day
of month, month, day of week) followed by what to run. systemd splits that into two files. The
.service unit says what to run (ExecStart=), and a
.timer unit with the same name says when (OnCalendar=).
You enable the timer, not the service.
OnCalendar= reads like a timestamp with wildcards: DayOfWeek Year-Month-Day
Hour:Minute:Second. So cron's 30 3 * * 1-5 becomes
Mon..Fri *-*-* 03:30:00. Ranges use .. instead of -,
and a step is written as start/step, so */15 in the minute field
becomes *:00/15:00. The full grammar is in man systemd.time (section
"Calendar Events"); the cron side is in man 5 crontab.
One rule does not translate directly. When both the day-of-month and the day-of-week fields are
restricted, cron runs the job if either matches; OnCalendar= requires
both. A timer may list several OnCalendar= lines and fires when any of
them matches, so the converter splits such a job into two lines. Timers also add what cron lacks:
Persistent=true catches up on runs missed while the machine was off,
RandomizedDelaySec= spreads the start time, and output lands in the journal.
Worked examples
A nightly backup on weekdays
Input 30 3 * * 1-5 /usr/local/bin/backup.sh gives OnCalendar=Mon..Fri *-*-* 03:30:00
Cron's 1-5 becomes Mon..Fri and the time moves to the end as HH:MM:SS. The command goes into backup.service as ExecStart=/usr/local/bin/backup.sh; with Persistent=true a run missed while the machine was off happens at the next boot.
Every 15 minutes
Input */15 * * * * gives OnCalendar=*-*-* *:00/15:00
Cron's */15 becomes the systemd repetition 00/15: start at minute 0, repeat every 15 minutes. systemd-analyze calendar '*:0/15' shows the same expression in normalised form.
Day of month and weekday both set
Input 0 0 1,15 * 1 gives OnCalendar=*-*-01,15 00:00:00; OnCalendar=Mon *-*-* 00:00:00
Cron runs this on the 1st, the 15th AND every Monday. A single OnCalendar= line would mean 'the 1st or 15th, only if it is a Monday', so the timer gets two OnCalendar= lines instead.
Frequently asked questions
How do I convert a cron job to a systemd timer?
Create a .service file with ExecStart= set to the cron command and a .timer file with the same name holding OnCalendar=, then enable the timer. For a user job: save both in ~/.config/systemd/user/, run systemctl --user daemon-reload && systemctl --user enable --now name.timer, and check it with systemctl --user list-timers.
Why does my timer not match cron when I set both day of month and day of week?
Because cron uses OR and OnCalendar= uses AND for those two fields. In cron, 0 0 13 * 5 runs on every 13th and on every Friday; in systemd, Fri *-*-13 runs only on Friday the 13th. Cron switches to AND when either field starts with *, so 0 0 */2 * 1 means odd days that are Mondays. The fix is two OnCalendar= lines in one timer, which this tool writes for you.
Does a systemd timer run jobs that were missed while the computer was off?
Yes, if the timer has Persistent=true. systemd stores the last run time and starts the job once at boot when a run was missed, much like anacron. Plain cron skips missed runs. Persistent= only affects OnCalendar= timers (see man systemd.timer).
Why does my user timer not run when I am logged out?
User timers only run while your user's systemd instance is running, which by default is from login to logout. Run loginctl enable-linger $USER once to start your user manager at boot and keep it running; or install the units as system units in /etc/systemd/system/ instead.
Where does the output go, now that cron no longer emails it?
Into the journal. Read it with journalctl --user -u name.service (or without --user for a system unit). To get mail on failure, add OnFailure= pointing at a unit that sends the message.
How do I test an OnCalendar expression?
Run systemd-analyze calendar --iterations=5 'Mon..Fri *-*-* 03:30:00'. It prints the normalised form and the next 5 times the expression matches; the run times on this page are computed the same way in your browser. After enabling, systemctl list-timers shows the next trigger.