Timers — systemd's Replacement for Cron
systemd in Depth
Chapter 7 · Timers — systemd's Replacement for Cron
systemd1-3's own Type=oneshot material previewed exactly this chapter. Timers are systemd's own scheduled-task mechanism — genuinely different from cron, not just a reskinned version of it.
The Two-Unit Pattern — .timer + .service
A systemd timer is genuinely two separate unit files working together: a .timer unit defining when to run, and a .service unit defining what to run — by convention, sharing the same base name (backup.timer + backup.service). A deliberate design decision distinct from cron: the "what" is a real, independently-runnable systemd service — exactly systemd1-3's own Type=oneshot material — cleanly separated from the "when." You can run and test the service directly at any time with systemctl start backup.service, with no need to wait for or fake the timer at all.
OnCalendar= — Scheduling Syntax
The general shape: DayOfWeek Year-Month-Day Hour:Minute:Second, with wildcards (*) and shorthand keywords (daily/weekly/monthly/hourly) covering common cases without needing the full explicit syntax.
Verifies a calendar expression means what you think it means before deploying it, printing the next several actual trigger times — genuinely worth running on any expression before trusting it.
A Full Worked Timer Example
Notice: you enable and start the timer, not the service directly — the timer itself then triggers the service at the scheduled time. WantedBy=timers.target is systemd1-5's own target material made concrete for a specific new case — a dedicated target that exists purely to group active timers.
Persistent=true — Catching Up Missed Runs
The real, standout advantage over cron. Persistent=true tells systemd to check, at boot, whether this timer's scheduled trigger was missed while the system was off — a laptop shut down overnight through the scheduled 3am backup, for instance — and if so, run it once, immediately, upon boot, rather than silently skipping that day entirely. Traditional cron has no native equivalent: a missed cron job, with the system off at the scheduled time, is simply missed, silently, until the next scheduled occurrence.
Direct Comparison Against Traditional Cron
Real, concrete advantages: dependency-awareness (a timer's own service can Wants=/After= other units — waiting for a network mount before running a backup, genuinely impossible to express cleanly in a crontab); automatic journald logging (systemd1-6's own material — every timer-triggered run is automatically logged and queryable via journalctl -u backup.service, unlike cron's own historical reliance on separate mail-based or ad-hoc logging); Persistent=true's own missed-run catch-up; and direct testability, per this chapter's own opening point. An honest note: cron's own crontab syntax is genuinely more compact for the simplest cases, and cron remains extremely widely deployed and understood — this isn't a "cron is bad" chapter, just an honest accounting of what systemd timers genuinely add.
| Missed run (system off) | Dependency-aware? | Logging | |
|---|---|---|---|
| cron | Silently skipped | No | Separate, ad-hoc |
| systemd timer | Caught up on boot with Persistent=true | Yes — via the paired service's own Wants=/After= | Automatic, via journald |
systemctl list-timers shows every active timer on the system, along with its next scheduled trigger time — a genuinely useful, quick "what's actually scheduled on this box" overview.
.timer unit's own [Install] section, systemctl enable has nothing to actually attach the timer to. It may appear to work when started manually, but won't behave the way a genuinely enabled unit should — always include it.
Hands-On Exercises
Write a complete .timer unit (matching this chapter's own backup.timer structure) that runs a paired service every Sunday at 02:30, with missed-run catch-up enabled.
📄 View solutionExplain why the two-unit .timer/.service pattern makes testing a scheduled task genuinely easier than testing a traditional cron job, referencing this chapter's own opening point directly.
📄 View solutionA laptop is shut down at the exact moment its nightly backup.timer would have triggered, and stays off until the next afternoon. Explain what happens when it's finally turned back on, assuming Persistent=true is set.
📄 View solutionChapter 7 Quick Reference
- A systemd timer is two paired units: .timer (when) + .service (what, matching systemd1-3's own Type=oneshot)
- OnCalendar= — daily/weekly/monthly/hourly shorthand, or explicit DayOfWeek Year-Month-Day Hour:Min:Sec syntax
systemd-analyze calendar "expr"— verify a schedule before deploying it- Enable/start the timer, not the service; WantedBy=timers.target is required for proper enabling
- Persistent=true — catches up a missed run on boot, no cron equivalent
- Real advantages over cron: dependency-awareness, automatic journald logging, missed-run catch-up, direct testability
systemctl list-timers— every active timer and its next scheduled run