systemctl list-timers --all

systemd Timer Builder

A systemd timer needs two files, not one. Pick a schedule and this builds the .timer and its matching .service together, plus the commands to install and check them.

Produces backup.timer and backup.service. No extension.
Must be an absolute path. systemd does not use your shell PATH.
Verify with: systemd-analyze calendar '<expression>'
Empty means root.
Spreads load across machines.

Timers versus cron

A timer beats a cron job when you care about what happened. Timer runs are real systemd units, so they get journal entries, exit codes, dependency ordering, and resource limits. Persistent=true catches up a missed run after the machine was off, which cron cannot do at all. The cost is two files instead of one line. Use RandomizedDelaySec on anything that hits a shared server, so twenty machines do not all start at 03:00:00 exactly.

Generate systemd timer and service units

This systemd timer generator writes both halves of a scheduled task: the .timer that defines when it runs and the .service that defines what runs. It covers OnCalendar expressions, Persistent catch-up, randomised delay, user units, and the systemctl commands to install, enable, and inspect the result. If you are migrating from cron, the crontab generator covers the other side.

systemd timer FAQ

Why do I need two files for one scheduled task?

systemd separates scheduling from work. The .timer says when, the .service says what. That split is why a timer can reuse an existing service, why you can trigger the same job manually with systemctl start, and why the run shows up in the journal as a normal unit.

What does Persistent=true actually do?

It records when the timer last fired. If the machine was off or suspended when a run was due, the job executes shortly after the next boot instead of being skipped. cron has no equivalent, which is why laptop backups scheduled with cron so often never run.

How do I check my OnCalendar expression is right?

Run systemd-analyze calendar 'your-expression'. It prints the normalised form and the next several trigger times. Always do this before installing, because a syntactically valid expression can easily mean something other than you intended.

Why does my command work in a terminal but fail in the timer?

Almost always PATH or environment. systemd services run with a minimal environment and no shell profile, so use absolute paths for every binary, and set Environment= or EnvironmentFile= for anything the script expects. Check journalctl -u yourunit.service for the actual error.