systemd timer directives¶
Synopsis¶
# /etc/systemd/system/<NAME>.timer
[Unit]
Description=<one-line description>
[Timer]
OnCalendar=<calendar event> …
OnActiveSec=<time span>
OnBootSec=<time span>
OnStartupSec=<time span>
OnUnitActiveSec=<time span>
OnUnitInactiveSec=<time span>
AccuracySec=<time span>
RandomizedDelaySec=<time span>
FixedRandomDelay=yes|no
RandomizedOffsetSec=<time span>
DeferReactivation=yes|no
OnClockChange=yes|no
OnTimezoneChange=yes|no
Persistent=yes|no
WakeSystem=yes|no
RemainAfterElapse=yes|no
Unit=<unit>
[Install]
WantedBy=timers.target
<NAME> is the timer's name without its suffix.
Description¶
A timer unit (suffix .timer) makes systemd start another unit when a time is reached.
By default it starts the service with the same name: <NAME>.timer starts <NAME>.service, which must exist.
The timer itself contains no command.
If the unit to be started is still active when the timer elapses, systemd leaves it running and doesn't start a second instance.
Timer units use the same file syntax, search paths and [Unit] and [Install] sections as other units; see systemd unit directives.
Unless DefaultDependencies=no is set, a timer gets Requires= and After= on sysinit.target, Before= on timers.target, and Conflicts= and Before= on shutdown.target; a timer with OnCalendar= is also ordered After= time-set.target and time-sync.target.
A timer is also ordered Before= the unit it starts.
Timer units are a feature of the systemd service manager. OpenRC has no equivalent; on Gentoo with OpenRC, scheduled jobs use cron (see crontab syntax).
Checked against systemd 257 on Debian 13, AlmaLinux 10 and Rocky Linux 10, systemd 259 on Ubuntu 26.04 and systemd 262 on Arch Linux (November 2026).
[Timer] directives¶
When the timer elapses¶
| Directive | Value | Elapses |
|---|---|---|
OnCalendar= |
Calendar event | At each wall-clock time matching the expression (see Calendar events) |
OnActiveSec= |
Time span | This long after the timer unit was started |
OnBootSec= |
Time span | This long after the machine booted |
OnStartupSec= |
Time span | This long after the service manager started; for system timers almost the same as OnBootSec=, for user timers relative to the start of the user's service manager |
OnUnitActiveSec= |
Time span | This long after the unit the timer starts was last activated |
OnUnitInactiveSec= |
Time span | This long after the unit the timer starts was last deactivated |
OnClockChange= |
Boolean, default no |
When the system clock jumps relative to the monotonic clock |
OnTimezoneChange= |
Boolean, default no |
When the system time zone changes |
OnCalendar=defines a realtime timer; theOn…Sec=directives define monotonic timers, which don't depend on the wall clock or time zone and normally pause while the system is suspended.- Every directive in the table may be given more than once, and realtime and monotonic directives may be combined in one timer. The timer elapses whenever any of them elapses.
- Assigning an empty value to any of
OnCalendar=,OnActiveSec=,OnBootSec=,OnStartupSec=,OnUnitActiveSec=orOnUnitInactiveSec=clears all realtime and monotonic timers set before it (useful in drop-ins). - If the time given by
OnBootSec=orOnStartupSec=is already in the past when the timer is started, the timer elapses immediately. This doesn't apply to the other monotonic directives. - A repeating interval is commonly written as
OnBootSec=combined withOnUnitActiveSec=, for example "15 minutes after boot, then every hour". - If a calendar timer elapses while the system is suspended, it's handled once after resume, however many times it elapsed during the sleep.
Timing adjustments¶
| Directive | Default | Effect |
|---|---|---|
AccuracySec= |
1min |
systemd may delay each elapse by up to this span, at a host-specific stable point, to group wake-ups of several timers. 1us gives the best accuracy |
RandomizedDelaySec= |
0 |
Delays each elapse by a random time between 0 and this span, chosen anew for each elapse. Counted from the scheduled time or from the service manager's start, whichever is later |
FixedRandomDelay= |
no |
With RandomizedDelaySec=: the delay is derived from the machine ID, the user and the unit name, so it's the same on every elapse and after restarts (systemd 247 and later) |
RandomizedOffsetSec= |
0 |
OnCalendar= timers only: adds a stable offset between 0 and this span, derived like FixedRandomDelay=, independently of the service manager's start time, so the schedule's period is kept across reboots (systemd 258 and later: Ubuntu 26.04 and Arch, not Debian 13 or RHEL 10) |
DeferReactivation= |
no |
OnCalendar= timers only: computes the next elapse from when the started unit became inactive, not from the last trigger, so a job that runs longer than the interval doesn't start again immediately after it finishes (systemd 257 and later) |
When RandomizedDelaySec= and AccuracySec= are both in effect, the random delay is added first and the result may then be shifted by up to AccuracySec=.
To spread elapses evenly over a range, set AccuracySec=1us together with RandomizedDelaySec=.
Behaviour¶
| Directive | Default | Effect |
|---|---|---|
Persistent= |
no |
OnCalendar= timers only: stores the time of the last trigger on disk; when the timer is started (for example at boot) and an elapse was missed while it was inactive, the unit is started immediately, subject to RandomizedDelaySec= |
WakeSystem= |
no |
Resumes the system from suspend when the timer elapses, if the hardware supports it; also makes monotonic timers use a clock that keeps running during suspend. System timers only |
RemainAfterElapse= |
yes |
Keeps an elapsed timer that can't elapse again loaded and queryable. With no, such a timer is unloaded once its unit has finished, which suits transient timers |
Unit= |
<NAME>.service |
The unit to start; any unit type except .timer |
systemctl clean --what=state <NAME>.timer removes the timestamp stored by Persistent=.
Calendar events¶
| Part | Syntax |
|---|---|
| Weekdays | English names, abbreviated (Mon) or full (Monday), any case; lists with ,, ranges with .. (Mon..Fri). Optional: without it, every day matches |
| Date | YEAR-MONTH-DAY. Omitted: *-*-* |
| Time | HOUR:MINUTE[:SECOND]. Omitted: 00:00:00. Omitted seconds: :00 |
* |
Any value of that component |
, |
List of values: 06,18:00 |
.. |
Range: 9..17:00 |
/N |
The value and every Nth value after it: *:0/15 (minute 0, 15, 30 and 45); also after a range |
~ |
In the day field, counts back from the end of the month: *-02~03 is the third-last day of February |
| Seconds | May have decimal fractions, rounded to 6 places |
| Time zone | UTC, or an IANA time zone name such as Europe/Berlin. Omitted: the system's local time zone |
A weekday together with a day of the month must match both: Fri *-*-1..7 12:00 is noon on the first Friday of each month.
| Shorthand | Normalised form |
|---|---|
minutely |
*-*-* *:*:00 |
hourly |
*-*-* *:00:00 |
daily |
*-*-* 00:00:00 |
weekly |
Mon *-*-* 00:00:00 |
monthly |
*-*-01 00:00:00 |
quarterly |
*-01,04,07,10-01 00:00:00 |
semiannually |
*-01,07-01 00:00:00 |
yearly, annually |
*-01-01 00:00:00 |
Time spans¶
A time span is a number with a unit, or several such terms, which are added: 1h 30min, 90s, 2d.
Spaces between terms may be omitted.
A number without a unit means seconds in all the …Sec= directives above.
| Unit | Accepted forms |
|---|---|
| Microseconds | usec, us, μs |
| Milliseconds | msec, ms |
| Seconds | seconds, second, sec, s |
| Minutes | minutes, minute, min, m |
| Hours | hours, hour, hr, h |
| Days | days, day, d |
| Weeks | weeks, week, w |
| Months | months, month, M (30.44 days) |
| Years | years, year, y (365.25 days) |
Commands¶
| Command | Effect |
|---|---|
systemctl list-timers [--all] [PATTERN] |
Lists timers with their next and last elapse; --all includes inactive timers |
systemctl enable --now <NAME>.timer |
Starts the timer at boot (via timers.target) and now |
systemctl start <NAME>.service |
Runs the job immediately, independently of the timer |
systemctl status <NAME>.timer |
Shows the timer's state and next elapse |
systemctl show <NAME>.timer -p TimersCalendar,TimersMonotonic,LastTriggerUSec,NextElapseUSecRealtime |
Shows the parsed schedule and trigger times as properties |
systemd-analyze calendar [--iterations=N] 'EXPRESSION' … |
Normalises a calendar event and shows its next N elapses |
systemd-analyze timespan 'SPAN' … |
Normalises a time span and shows it in microseconds |
systemd-analyze verify <FILE> |
Checks unit files for errors |
systemd-run --on-calendar='EXPRESSION' COMMAND |
Creates a transient timer and service for a command (also --on-active=, --on-boot=, --on-unit-active=) |
journalctl -u <NAME>.service |
Shows the job's output from every run |
Examples¶
Normalised forms and next elapses printed by systemd-analyze calendar (systemd 257 on Debian 13, on Saturday 7 November 2026 at about 13:27 UTC):
$ systemd-analyze calendar --iterations=2 'Mon..Fri 02:30'
Original form: Mon..Fri 02:30
Normalized form: Mon..Fri *-*-* 02:30:00
Next elapse: Mon 2026-11-09 02:30:00 UTC
From now: 1 day 13h left
Iteration #2: Tue 2026-11-10 02:30:00 UTC
From now: 2 days left
$ systemd-analyze calendar '*:0/15'
Original form: *:0/15
Normalized form: *-*-* *:00/15:00
Next elapse: Sat 2026-11-07 13:30:00 UTC
From now: 2min 16s left
$ systemd-analyze calendar '2026-12-25 08:00 Europe/Berlin'
Original form: 2026-12-25 08:00 Europe/Berlin
Normalized form: 2026-12-25 08:00:00 Europe/Berlin
Next elapse: Fri 2026-12-25 07:00:00 UTC
From now: 1 month 17 days left
$ systemd-analyze timespan '1h 30min'
Original: 1h 30min
μs: 5400000000
Human: 1h 30min
A daily job at 02:30, caught up after downtime and spread over 10 minutes:
A job 15 minutes after boot, then every 6 hours after it last started:
A timer that starts a differently named service:
A step-by-step example is in How to schedule a job with a systemd timer.
Files¶
| Path | Purpose |
|---|---|
/etc/systemd/system/<NAME>.timer |
Timer units created by the administrator |
/usr/lib/systemd/system/*.timer |
Timer units installed by packages |
/var/lib/systemd/timers/stamp-<NAME>.timer |
Time of the last trigger of a system timer with Persistent=true (its modification time) |
/etc/systemd/system/timers.target.wants/ |
Symbolic links created by systemctl enable for timers with WantedBy=timers.target |
~/.config/systemd/user/<NAME>.timer |
A user's own timers, managed with systemctl --user |
See also¶
systemd.timer(5),systemd.time(7),systemd.unit(5),systemd.special(7),systemd-analyze(1),systemd-run(1)- systemd.timer, latest upstream version and systemd.time (check the "Added in version" notes against your installed version with
systemctl --version)
Related¶
- How-to: How to schedule a job with a systemd timer
- How-to: How to schedule a job with cron
- How-to: How to write a safe shell script
- Explanation: cron and systemd timers
- Explanation: Idempotency and configuration management
- Reference: crontab syntax
- Reference: systemd unit directives
- Tutorial: Configure a server with Ansible