Turn a cron line into a systemd timer, instantly.
Paste your crontab entry. Get a ready-to-save .timer and .service file, a plain-English schedule, and the next five run times. All in your browser.
How Cron to systemd Timer Converter works
- 1
Paste a crontab line
Paste a standard 5-field cron line with its command, or a macro like @daily, @hourly, or @reboot followed by the command to run.
- 2
The schedule is parsed entirely in your browser
Nothing is sent to a server. The five cron fields (or the expanded macro) are validated and translated field by field into systemd's OnCalendar= syntax.
- 3
The day-of-month / day-of-week OR trap is detected
If your schedule restricts both fields at once, a warning explains the difference between cron's OR behavior and systemd's AND behavior, and the tool emits two OnCalendar= lines to reproduce cron's semantics exactly.
- 4
A .service and .timer file are generated
The .service file wraps your command with Type=oneshot. The .timer file gets the OnCalendar= line(s), an optional Persistent=true, and WantedBy=timers.target.
- 5
Toggle User or System mode
Switching the mode updates the save-and-enable commands to match: user units go in ~/.config/systemd/user/ with systemctl --user, system units go in /etc/systemd/system/ with plain systemctl.
- 6
Copy the files and the enable commands
Save the two files with the suggested name, run the daemon-reload and enable command shown, and (for user mode) enable lingering so the timer survives logout.
What each generated file does
Every cron job becomes exactly two systemd unit files.
Defines what actually runs. Type=oneshot tells systemd this unit runs once and exits, rather than staying resident, which matches how a cron job behaves.
[Unit]
Description=my-job
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.shDefines when the .service runs. OnCalendar= is the schedule itself, Persistent=true (optional) catches up on a missed run after downtime, and WantedBy=timers.target makes the timer start automatically.
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.targetShown only when both day-of-month and day-of-week are restricted in your cron line. Two OnCalendar= lines are generated instead of one, since systemd unions them, to correctly reproduce cron's OR semantics.
OnCalendar=*-*-01 00:00:00
OnCalendar=Sun *-*-* 00:00:00The exact commands to copy the two files into place, reload systemd, and enable the timer, adjusted automatically for User vs System mode.
systemctl --user daemon-reload
systemctl --user enable --now my-job.timerCron and OnCalendar syntax reference
What's supported on input, and what it maps to on output.
# Cron: minute hour day-of-month month day-of-week
# Fields: 0-59 0-23 1-31 1-12 0-7 (0 and 7 both = Sunday)
* -> * (any value, in either syntax)
*/15 -> 0/15 (step values)
1-5 -> 1..5 (ranges use .. in OnCalendar)
1,15 -> 1,15 (comma lists, unchanged)
dow: 1-5 -> Mon..Fri (weekday numbers become names)
dow: 0 or 7 -> Sun
# Macros expand before conversion:
@yearly / @annually -> 0 0 1 1 *
@monthly -> 0 0 1 * *
@weekly -> 0 0 * * 0
@daily / @midnight -> 0 0 * * *
@hourly -> 0 * * * *
@reboot -> OnBootSec=0 (no OnCalendar= at all)Already comfortable with cron and just need to build or double-check an expression first? Our Cron Expression Builder handles that half separately, with a visual field editor and its own next-run preview.
When to use Cron to systemd Timer Converter
| Scenario |
|---|
| Migrating a server off cron onto systemd |
| You inherited a crontab from a previous admin |
| Want missed-run recovery on a laptop or workstation |
| Setting up a rootless container host |
| Double-checking a day-of-month + day-of-week schedule |
| Converting a @reboot cron entry |
Frequently Asked Questions
What is systemd OnCalendar syntax?
OnCalendar= is the directive systemd timers use to define a recurring schedule. It follows the format weekday year-month-day hour:minute:second, where each component supports lists (,), ranges (..), wildcards (*), and step values (/).
*-*-* 02:00:00 # every day at 2:00 AM
Mon..Fri *-*-* 09:00:00 # weekdays at 9:00 AM
*-*-* *:0/15:00 # every 15 minutes
*-01-01 00:00:00 # New Year's Day at midnightCheck what a timer will actually do before deploying it with systemd-analyze calendar "Mon..Fri *-*-* 09:00:00", which prints the next several trigger times.
Does this replace cron entirely?
Not necessarily, but systemd timers cover everything cron does and add a few things cron can't: Persistent=true catches up on a missed run after the machine was off, output goes to journalctl alongside every other service's logs, and Requires=/After= let a timer's job depend on another service being up first.
Plain cron is still perfectly fine for simple, low-stakes personal scripts. Systemd timers are the better choice for anything running on a server you actually monitor.
What's the difference between the User and System toggle?
| User (rootless) | System (rootful) | |
|---|---|---|
| Unit file location | ~/.config/systemd/user/ | /etc/systemd/system/ |
| Managed with | systemctl --user ... | systemctl ... (no --user) |
| Runs as | Your user | root |
| Survives logout by default | No, needs enable-linger | Yes, always |
Default to User mode unless the job genuinely needs root privileges. If you pick User mode, remember to run loginctl enable-linger $USER once, or the timer stops the moment you log out.
Does this tool send my crontab or server details to a server?
No. Parsing the cron line, computing the next run times, and generating the unit files all happen in JavaScript inside your browser. Nothing, including your commands, paths, or job names, is sent anywhere.
How do I convert a real crontab line, step by step?
Paste the exact line from crontab -l, including the command, then copy the two generated files to the location shown in the "Save and enable" block:
# 1. See your existing crontab
crontab -l
# 2. Paste a line like this into the tool above:
# 0 2 * * * /usr/local/bin/backup.sh
# 3. Save the generated files, then reload and enable (user mode shown):
mkdir -p ~/.config/systemd/user
cp my-job.service my-job.timer ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now my-job.timer
# 4. Remove the old cron entry once you've confirmed the timer works
crontab -eFor a full worked example converting a multi-service Docker Compose stack (not just a scheduled job) to systemd, see our Docker Compose to Podman Quadlet migration guide.
Why did I get two OnCalendar= lines instead of one?
This happens when your cron line restricts both the day-of-month and the day-of-week fields at the same time, for example 0 0 1 * 0 (the 1st of the month, or every Sunday).
Cron treats that combination as an OR: the job runs if either condition matches. A single systemd OnCalendar= expression with both a weekday and a day-of-month set is an AND instead, which would silently narrow your schedule. Since systemd unions multiple OnCalendar= directives in the same [Timer] section, the tool generates one line per condition to reproduce cron's OR behavior correctly.