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.

Options
OnCalendar=
Mon..Fri *-*-* 03:30:00
Meaning
Every weekday (Monday to Friday) at 03:30
Next 5 runs
  1. Calculated in your browser, in your own time zone.

    User timers run only while your user manager runs. To keep them running when you are logged out: loginctl enable-linger $USER

    Unit files

    Save as ~/.config/systemd/user/backup.timer

    [Unit]
    Description=Run backup.service on schedule
    
    [Timer]
    OnCalendar=Mon..Fri *-*-* 03:30:00
    Persistent=true
    
    [Install]
    WantedBy=timers.target
    

    Save as ~/.config/systemd/user/backup.service

    [Unit]
    Description=backup (converted from cron: 30 3 * * 1-5)
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/backup.sh
    

    Then load and start the timer:

    systemctl --user daemon-reload && systemctl --user enable --now backup.timer

    OnCalendar to cron

    Cron
    30 3 * * 1-5
    Meaning
    Every weekday (Monday to Friday) at 03:30

      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.