Platform schedule guide

systemd Timer and OnCalendar Guide

Replace cron with systemd timers. Learn OnCalendar syntax, timer and service units, timezone handling, Persistent catch-up, AccuracySec, randomized delay, validation, and operations.

Platform behavior reviewed against the official documentation on August 5, 2026.

Format
OnCalendar, not cron
Default timezone
System local zone
Missed-run option
Persistent=true
Default accuracy
1 minute

Overview

A systemd timer schedules another systemd unit, normally a service with the same base name. Calendar timers use OnCalendar expressions; monotonic timers use durations such as OnBootSec and OnUnitActiveSec. Neither form is a literal cron expression.

Timers integrate with service dependencies, resource controls, journal logs, status inspection, and missed-run catch-up. That makes them a strong replacement for machine-local cron when the host already uses systemd.

OnCalendar can express seconds, dates, ranges, lists, repetition, weekdays, and timezones. Validate every expression on the target system with systemd-analyze calendar because supported syntax can depend on the installed systemd version.

systemd OnCalendar format

A full calendar event can include weekday, date, time, and timezone. Omitted date components default to every date, and omitted seconds default to :00. Shorthands such as hourly, daily, weekly, monthly, and yearly improve readability.

Use OnCalendar for wall-clock events. Use OnBootSec, OnActiveSec, OnUnitActiveSec, or OnUnitInactiveSec when the requirement is a duration relative to boot, activation, or the service lifecycle.

[weekday] [year-month-day] [hour:minute:second] [timezone]

Mon..Fri *-*-* 09:00:00 Europe/Istanbul
*-*-* *:00/5:00 UTC
*-*-01 02:30:00
systemd timers schedule fields and valid values
FieldPositionValuesPlatform note
WeekdayOptionalMon-Sun, lists, rangesEnglish names; Mon..Fri is a continuous range.
DateOptionalyear-month-day* matches any component; lists, ranges, and repetition are available.
TimeOptionalhour:minute:secondSeconds default to 00 when omitted.
TimezoneOptionalUTC or IANA zoneWithout it, the system local timezone is used.

Copyable schedule examples

At the top of every hour

hourly

Every five minutes

*-*-* *:00/5:00

Weekdays at 09:00 in the system timezone

Mon..Fri *-*-* 09:00:00

Every Sunday at 02:00 UTC

Sun *-*-* 02:00:00 UTC

First day of every month at midnight

*-*-01 00:00:00

January, April, July, and October 1 at midnight

quarterly

Complete service and timer units

Create matching .service and .timer files. The timer activates backup.service, while the service owns the command, user, security controls, and completion status.

# /etc/systemd/system/backup.service
[Unit]
Description=Nightly application backup

[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/application-backup

# /etc/systemd/system/backup.timer
[Unit]
Description=Run application backup every night

[Timer]
OnCalendar=*-*-* 02:17:00 UTC
Persistent=true
AccuracySec=1min
RandomizedDelaySec=5min

[Install]
WantedBy=timers.target

Deployment checklist

  1. Validate the expression with systemd-analyze calendar and inspect several next occurrences.
  2. Run systemctl daemon-reload, then start a manual systemctl start backup.service test.
  3. Enable the schedule with systemctl enable --now backup.timer.
  4. Inspect systemctl list-timers, systemctl status backup.timer, and journalctl -u backup.service.

Timezone, accuracy, and missed runs

An OnCalendar expression uses the system local timezone unless it ends with UTC or an installed IANA timezone such as Europe/Istanbul. Putting the timezone in the expression makes the unit portable across hosts with different local settings.

Calendar events follow the selected timezone’s civil-time rules, so DST can make intervals shorter or longer. Use systemd-analyze calendar with the exact expression on the target version and avoid ambiguous transition times for non-repeatable work.

AccuracySec defaults to one minute and allows systemd to coalesce wakeups. RandomizedDelaySec deliberately spreads work over a window. Persistent=true causes one immediate catch-up activation when at least one calendar event was missed while the timer was inactive; it does not replay every missed occurrence.

systemd-analyze calendar   'Mon..Fri *-*-* 09:00:00 Europe/Istanbul'

systemctl list-timers --all
journalctl -u backup.service --since today

Limits and platform behavior

Not cron syntax
Do not paste a five-field cron expression into OnCalendar. Convert the intent into systemd calendar syntax.
Version-dependent features
Newer systemd releases add syntax and timer controls. Validate on the oldest supported host instead of relying on a desktop version.
Activation, not a shell line
The timer activates a unit. Put commands, environment, user identity, and hardening in the associated service.
One missed-run catch-up
Persistent=true catches up with an activation if one or more runs were missed; it does not enqueue one execution for each missed timestamp.

Production gotchas

  • Assuming exact timing

    AccuracySec and randomized delay affect activation time. Set them deliberately, but keep jobs correct even if the process starts late.

  • Testing only the timer

    Start the service directly before enabling the timer. This separates command, permission, and environment failures from scheduling failures.

  • Relative timer drift

    OnUnitActiveSec is relative to activation, not a fixed wall-clock schedule. Pick a monotonic or calendar timer based on the actual requirement.

  • Environment mismatch

    A service does not inherit an interactive shell environment. Use absolute paths and declare required Environment or EnvironmentFile values.

Frequently asked questions

Is systemd OnCalendar the same as cron syntax?

No. OnCalendar uses systemd calendar event syntax. It can express weekdays, full dates, times, seconds, and timezones, but a five-field cron string must be converted.

How do I catch up a missed systemd timer?

Set Persistent=true on an OnCalendar timer. When the timer becomes active, systemd triggers the service if at least one occurrence was missed while inactive.

What timezone does a systemd timer use?

OnCalendar uses the system local timezone unless the expression specifies UTC or an installed IANA timezone.

How do I test an OnCalendar expression?

Run systemd-analyze calendar followed by the quoted expression. It normalizes the schedule and prints upcoming occurrences.

Official documentation and related guides