« Back to systemd

Systemd timers

Systemd timers are the equivalent of cron and cronjobs. For modern Linux systems they most likely are a full replacement, including additional features.

Timers in systemd can be recognized by their extension .timer and are plaintext files that include their configuration. They describe what should happen, when, and if their are specific conditions that need to be met. It may include additional information like documentation and comments.

One important thing to know upfront when using timers is that a timer does not come alone. It is a trigger for a service unit (.service) and therefore should have the same name. The only difference in the name is obviously the file extension.

Additional benefits of timers

Timers have a few additional benefits that typically does not exist in cron or requires additional work.

Detailed management

Systemd units and their status are tracked carefully. Details such as activation and last execution are stored. This makes it easy to see when a task was performed. In the case of timers, we can also see when it will be performed in the near future. With cron this is harder to see, especially when jobs are divided over multiple locations (crontab, cron.hourly, cron.daily, cron.weekly, etc).

Delayed start after boot

One of the options is to start a task just after the system is booted, like updating software packages. But as the system will be very busy just after the start, it might be useful to wait for a few minutes. This can be achieved using the OnBootSec setting, part of the Timer section.

  • Setting: OnBootSec
  • Value: time
  • Section: Timer
  • Example: OnBootSec=5min

Delayed start with random time

When having many systems performing a task at the the same hour and minute, it can cause unneeded strain on the network, internet connection, or receiving systems. Timers can solve this issue by delaying the start time of a task with a random interval. The setting is RandomizedDelaySec and part of the Timer section.

While the setting would indicate the time is to be set in seconds, a time can also be specified, like 12h. This way the task will be delayed between 0 seconds and half a day.

  • Setting: RandomizedDelaySec
  • Value: time
  • Section: Timer
  • Example: RandomizedDelaySec=12h

Delay after unit activation

Sometimes you want to create a timer, but not directly active it. Maybe there is not enough data to process, or you want to wait till the next day. By defining OnUnitActiveSec in the Timer section, we can delay execution as well.

  • Setting: OnUnitActiveSec
  • Value: time
  • Section: Timer
  • Example: OnUnitActiveSec=24h

See available systemd timers

On a regular Linux distribution there will be timers defined by the distribution itself and as part of common software packages. Use the subcommand list-timers to show the existing timers.

# systemctl list-timers 
NEXT                        LEFT           LAST                        PASSED       UNIT                           ACTIVATES                       
Fri 2024-05-24 10:10:35 UTC 2h 27min left  Thu 2024-05-23 04:56:31 UTC 1 day 2h ago man-db.timer                   man-db.service
Fri 2024-05-24 11:48:14 UTC 4h 5min left   Thu 2024-05-23 19:57:03 UTC 11h ago      fwupd-refresh.timer            fwupd-refresh.service
Fri 2024-05-24 16:01:53 UTC 8h left        Thu 2024-05-23 19:56:56 UTC 11h ago      apt-daily.timer                apt-daily.service
Fri 2024-05-24 20:10:39 UTC 12h left       Fri 2024-05-24 04:47:52 UTC 2h 55min ago motd-news.timer                motd-news.service
Sat 2024-05-25 00:00:00 UTC 16h left       Fri 2024-05-24 00:00:21 UTC 7h ago       dpkg-db-backup.timer           dpkg-db-backup.service
Sat 2024-05-25 00:00:00 UTC 16h left       Fri 2024-05-24 00:00:21 UTC 7h ago       logrotate.timer                logrotate.service
Sat 2024-05-25 00:05:14 UTC 16h left       Fri 2024-05-24 00:05:14 UTC 7h ago       update-notifier-download.timer update-notifier-download.service
Sat 2024-05-25 00:16:14 UTC 16h left       Fri 2024-05-24 00:16:14 UTC 7h ago       systemd-tmpfiles-clean.timer   systemd-tmpfiles-clean.service
Sat 2024-05-25 06:06:59 UTC 22h left       Fri 2024-05-24 06:50:34 UTC 52min ago    apt-daily-upgrade.timer        apt-daily-upgrade.service
Sun 2024-05-26 03:10:58 UTC 1 day 19h left Sun 2024-05-19 03:11:03 UTC 5 days ago   e2scrub_all.timer              e2scrub_all.service
Mon 2024-05-27 01:04:09 UTC 2 days left    Mon 2024-05-20 00:01:32 UTC 4 days ago   fstrim.timer                   fstrim.service
Mon 2024-05-27 07:15:58 UTC 2 days left    Thu 2024-05-23 19:56:56 UTC 11h ago      update-notifier-motd.timer     update-notifier-motd.service

12 timers listed.
Pass --all to see loaded but inactive timers, too.

Besides the timing (next, left, last, passed), we can see the unit name, but also the column ACTIVATES.

How to see the configuration of a timer

In the column UNIT, when using list-timers, the file name is shown. This file name is not the full path, so it can be stored in a few common locations. Fortunately, you don’t have to know where it is located (yet). With the subcommand cat we can easily see the content of the timer file and its location.

# systemctl cat man-db.timer
# /lib/systemd/system/man-db.timer
[Unit]
Description=Daily man-db regeneration
Documentation=man:mandb(8)

[Timer]
OnCalendar=daily
RandomizedDelaySec=12h
Persistent=true

[Install]
WantedBy=timers.target

When using systemctl cat, the first line is displayed as a comment and refers to the full path of the unit file.

Status of a timer

To learn more about a particular timer and its status, we can query it using the status subcommand. Similar to a service, this will give us more insights, but tailored to the timer itself.

# systemctl status fstrim.timer
● fstrim.timer - Discard unused blocks once a week
     Loaded: loaded (/lib/systemd/system/fstrim.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Wed 2024-05-08 23:56:25 UTC; 2 weeks 1 day ago
    Trigger: Mon 2024-05-27 01:04:09 UTC; 2 days left
   Triggers: ● fstrim.service
       Docs: man:fstrim

May 08 23:56:25 webdev01 systemd[1]: Started Discard unused blocks once a week.

In this example, we can see that is is active and in 2 days the timer will be triggered. The Triggers line shows us the relevant service (fstrim.service).

Timer types and schedule

Timers are scheduled by their type. A monotonic timer is activated based on another event, such as activation of the unit or boot time. Examples of this type were already covered in the benefits above.

Another type of a real-time timer. It is planned by using a calendar event, like the day name (Monday) or specific hour of the day. This type is commonly used to run tasks on a repeating rate.

By day

When using the OnCalendar option, we can schedule a task daily, exactly at the hour/minute/second mark.

OnCalendar=Mon..Sun *-*-* 4:00:00

Another option is defining multiple ranges.

OnCalendar=Mon..Fri *-*-* 22:00
OnCalendar=Sat,Sun *-*-* 14:00

Multiple hours is also possible. To run a task daily at 6 AM and 6 PM, define the entry without a day and only the hours, separated by a comma.

OnCalendar=*-*-* 6,18:00

To repeat a task multiple times an hour, we can define this using a slash. For example, having the systemd timer run every 5 minutes.

OnCalendar=*-*-* *:0/5:00

Weekly

The easiest way to plan a task weekly is by using the weekly value.

OnCalendar=weekly

An alternative is to define the specific day and hour.

OnCalendar=Sun *-*-* 06:00:00

By specific day of the month

It is also possible to plan a task at the first of the month, or a specific month of the year.

OnCalendar=*-*-1 00:01

In March, daily? Set the month

OnCalendar=*-3-* 00:01

Only on Sunday if it is an even month.

OnCalendar=Sun *-2,4,6,8,10,12-* 00:01

As you can see, this system of scheduling is very flexible.

Testing your timer

Due to its flexibility, one might make an error. To learn when the next planned action would happen, we can use the systemd-analyze command with its subcommand calendar.

# systemd-analyze calendar "Sun *-6,8-* 00:01"
  Original form: Sun *-6,8-* 00:01
Normalized form: Sun *-06,08-* 00:01:00
    Next elapse: Sun 2024-06-02 00:01:00 UTC
       From now: 1 week 1 day left

Systemd timers commands

CommandGoal
systemctl cat UNIT.timerShow the content of a timer
systemctl enable UNIT.timeEnable the timer
systemctl list-timersShow active timers
systemctl list-timers PATTERNShow active timers that match a pattern (e.g. log*)
systemctl list-timers --allShow all timers, including inactive timers
systemctl start UNIT.timerStart the timer
systemctl status UNIT.timerShow status of the timer
systemctl stop UNIT.timerStop the timer

Converting from cron to systemd timers

Need to convert entries from cron to systemd? Here are a few common ones.

Cronsystemd timer
hourlyOnCalendar=--* *:00:00
dailyOnCalendar=--* 00:00:00
weeklyOnCalendar=Sun --* 00:00:00
monthlyOnCalendar=--01 00:00:00

Learn more about systemctl

This article uses the systemctl command to achieve its tasks. For this popular tool there is a cheat sheet available!

» Mastering the tool: systemctl

systemctl cheat sheet

Feedback

Small picture of Michael Boelen

This article has been written by our Linux security expert Michael Boelen. With focus on creating high-quality articles and relevant examples, he wants to improve the field of Linux security. No more web full of copy-pasted blog posts.

Discovered outdated information or have a question? Share your thoughts. Thanks for your contribution!

Mastodon icon