cron to systemd timer converter

Paste a cron schedule or a whole crontab line. You get what it means, when it runs next, and a systemd service and timer that do the same, with the commands that install them.

Five fields (minute hour day month weekday) or a macro such as @daily. A whole line from crontab -l is split for you.
As in crontab. A command with pipes, redirects, quotes or $ runs through /bin/sh -c, as cron runs it.
Both files take this name: <name>.service and <name>.timer.
The crontab's owner. Empty runs it as root, like /etc/crontab with root.
Optional, for example 5min: spreads the start over that window so servers do not all start at once.
If the server was off at the scheduled time, the job runs once at the next boot. cron (without anacron) skips it.
Off by default, because cron does not sandbox its jobs. On: /usr, /boot and /etc become read-only for the job.

What it means

At 02:30.

The same schedule in systemd's calendar format:

  • OnCalendar=*-*-* 02:30:00

Next five runs

The server reads OnCalendar= in its own time zone (timedatectl). Choose UTC if the server uses UTC.

Your service and timer

backup-nightly.service
# backup-nightly.service: Nightly backup
# Generated by @anaroq/linux 1.0.0 (ANAROQ).
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup --quiet
Restart=no
backup-nightly.timer
# backup-nightly.timer: Nightly backup
# Generated by @anaroq/linux 1.0.0 (ANAROQ).
# From cron "30 2 * * *": At 02:30.
[Unit]
Description=Nightly backup

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

Hand off to an agent

A Markdown task for a coding agent: the files, the findings, the limits and fixed guardrails. Values that look like secrets are masked. It is built on this page and sent nowhere.

How the agent handoff works

Install and start the timer

Run these on the server in the folder where you saved both files, then remove the line from the crontab so the job does not run twice.

install-commands.txt
sudo install -m 0644 backup-nightly.service /etc/systemd/system/backup-nightly.service
sudo install -m 0644 backup-nightly.timer /etc/systemd/system/backup-nightly.timer
sudo systemd-analyze verify /etc/systemd/system/backup-nightly.service /etc/systemd/system/backup-nightly.timer
sudo systemctl daemon-reload
sudo systemctl enable --now backup-nightly.timer
systemctl list-timers backup-nightly.timer
journalctl -u backup-nightly.service -f

What changes when cron becomes a timer

  • Output goes to the journal (journalctl -u <name>.service), not to an email from cron.
  • systemd runs the job with its own environment, not cron's short PATH. Use absolute paths, or set the variables in the service.
  • A timer does not start the job again while the last run is still going; cron would start a second copy.
  • With Persistent=true, a run missed while the server was off happens at the next boot.

Need a service that runs all the time? Write one with the systemd service generator

What it does

It reads a cron schedule the way cron does, says in words when it runs, lists the next five runs from a date you choose, and writes a systemd service and timer that run the same command on the same schedule.

How it works

  1. The schedule is read by @anaroq/linux, the engine behind our other Linux tools, with cron's ranges, steps, lists, month and weekday names and @ macros, and refused with the field and the reason when cron would not accept it.
  2. Each field becomes part of a systemd calendar expression. When both day fields are restricted, cron runs on either one, so the timer gets one OnCalendar= for each; when one of them starts with *, both must match, as in cron.
  3. The command runs directly when it needs no shell, and through /bin/sh -c otherwise. cron's own % rule has no systemd equivalent and is refused; \% becomes %.
  4. The next runs are computed in this browser from the date and time zone you choose; nothing is sent. Every golden output passes systemd-analyze verify and systemd-analyze calendar in our tests.

Common schedules

cronMeaningOnCalendar=
*/15 * * * *Every 15 minutes.*-*-* *:00/15:00
0 * * * *At minute 0 past the hour.*-*-* *:00:00
0 3 * * *At 03:00.*-*-* 03:00:00
30 2 * * 0At 02:30 on Sunday.Sun *-*-* 02:30:00
0 9-17 * * mon-friAt minute 0 past the hour, during hours 09–17 on Monday–Friday.Mon..Fri *-*-* 09..17:00:00
0 0 1 * *At 00:00 on day 1 of the month.*-*-01 00:00:00
0 4 1-7 * 1At 04:00 on days 1–7 of the month or on Monday.Mon *-*-* 04:00:00*-*-01..07 04:00:00
@rebootOnce, every time the server boots.OnBootSec=1min

Example

A nightly backup at 02:30 becomes this service and timer:

30 2 * * * /usr/local/bin/backup --quiet

At 02:30.

backup-nightly.service
# backup-nightly.service: Nightly backup
# Generated by @anaroq/linux 1.0.0 (ANAROQ).
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup --quiet
Restart=no
backup-nightly.timer
# backup-nightly.timer: Nightly backup
# Generated by @anaroq/linux 1.0.0 (ANAROQ).
# From cron "30 2 * * *": At 02:30.
[Unit]
Description=Nightly backup

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

The commands that install them

install-commands.txt
sudo install -m 0644 backup-nightly.service /etc/systemd/system/backup-nightly.service
sudo install -m 0644 backup-nightly.timer /etc/systemd/system/backup-nightly.timer
sudo systemd-analyze verify /etc/systemd/system/backup-nightly.service /etc/systemd/system/backup-nightly.timer
sudo systemctl daemon-reload
sudo systemctl enable --now backup-nightly.timer
systemctl list-timers backup-nightly.timer
journalctl -u backup-nightly.service -f

Limits

  • cron extensions such as L, W, # and ? (from Quartz or other schedulers) are not cron syntax and are refused.
  • The service runs as root unless you give the crontab's user. A user crontab's own environment (MAILTO, SHELL, PATH lines) is not converted.
  • The next runs follow the time zone you choose. On days the clocks change, a time that does not exist is skipped, and cron implementations differ there.
  • The timer replaces the crontab line; remove the line yourself, or the job runs twice.

Need a service that runs all the time? Write one with the systemd service generator

Sources

  1. systemd.service(5)
  2. systemd.exec(5)
  3. systemd.unit(5)
  4. systemd.timer(5)
  5. systemd-analyze(1)
  6. systemd.time(7): calendar events
  7. crontab(5) (cronie)

Updated

Next step

systemd service generator

A free public tool by ANAROQ, a company building compute infrastructure. What ANAROQ is building