Older versions of Linux use the cron daemon to schedule tasks. However, the cron daemon is no longer recommended for new installations. Instead, you should use the systemd timer. Cron dates back to a time when Linux systems were much simpler. While it still works, it has some structural drawbacks.
All of this can be handled with systemd-Timer. Therefore, this section will demonstrate the simple setup and administration of these timers.
Systemd is the init system of modern Linux distributions. Earlier versions used SysVInit, the init system under the Unix operating system System V, based on the UNIX philosophy of "one program, one task." Each service was started, configured, and stopped as an independent script. Systemd, on the other hand, is a monolithic init system. It therefore handles not only starting services but also logging (journald), timers, socket activation, and much more. This brings us to the heart of systemd's main tasks:
We've now established that systemd timers are ideally suited to replacing traditional cron jobs. So let's take a closer look at the structure of a timer. First, we'll display a list of all active timers on a Linux system using the command...
~# systemctl list-timers
This provides a list of timers, including the timer name, the next trigger time, and the last trigger time:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2026-03-02 00:00:00 CET 7h left Sun 2026-03-01 00:00:08 CET 16h ago dpkg-db-backup.timer dpkg-db-backup.service
Mon 2026-03-02 00:00:00 CET 7h left Sun 2026-03-01 00:00:08 CET 16h ago logrotate.timer logrotate.service
Mon 2026-03-02 04:41:29 CET 12h left Sun 2026-03-01 07:39:45 CET 8h ago apt-daily.timer apt-daily.service
Mon 2026-03-02 06:15:02 CET 13h left Sun 2026-03-01 06:18:19 CET 10h ago apt-daily-upgrade.timer apt-daily-upgrade.service
Mon 2026-03-02 08:21:42 CET 15h left Sun 2026-03-01 08:44:15 CET 7h ago man-db.timer man-db.service
Mon 2026-03-02 10:13:29 CET 17h left Sun 2026-03-01 10:13:29 CET 6h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Fri 2026-03-06 19:00:00 CET 5 days left Fri 2026-02-27 19:00:02 CET 1 day 21h ago securesnap.timer securesnap.service
Sun 2026-03-08 03:00:00 CET 6 days left Sun 2026-03-01 03:00:17 CET 13h ago backup2storage.timer backup2storage.service
Generally, as with all aspects outside the home directory, to set a timer you need the root user via “su -” or a user with sudo privileges.
Instead of a cron job, we're creating a systemd timer for the backup script “Securesnap” with
~# vi /etc/systemd/system/securesnap.timer
and the following content
[Unit]
Description=Timer for Securesnap Backup
[Timer]
OnCalendar=Fri 19:00
Persistent=true
Unit=securesnap.service
[Install]
WantedBy=timers.target
The three blocks "Unit", "Timer", and "Install" are mandatory. Of particular interest are OnCalendar for specifying the execution time, Persistent, Unit in the Timer block, and WantedBy in the Install block.
The Unit parameter in the timer block explicitly assigns the corresponding service, although this is actually achieved through the equivalent names for .timer and .service if systemctl start securesnap.timer were used directly. Persistent=true ensures that missed jobs are caught up on the next startup. This isn't necessary for regular jobs on servers, as servers run almost continuously, and if the intervals are moderate, this parameter can be safely ignored.
However, WantedBy=timers.target is required to activate the timer at boot.
As just seen in the timer definition, it makes no sense without the corresponding service. The equivalent service to this example timer would be /etc/systemd/system/securesnap.service:
[Unit]
Description=Weekly System Backup with Securesnap
[Service]
Type=oneshot
ExecStart=/usr/local/bin/securesnap.sh
[Install]
WantedBy=multi-user.target
Since this is a one-time job triggered by the timer, the parameter Type=oneshot is very important. Systemd waits for the process to complete before terminating the service.
Reloading the systemd configurations is very important, as we have modified them by creating a new timer and service. Systemd will only be aware of this after executing this command.
~# systemctl daemon-reload
The timer is started in this way:
~# systemctl start securesnap.timer
And to activate the timer at boot, this command is necessary:
~# systemctl enable securesnap.timer
The following command can be used to display the relevant timer:
~# systemctl list-timers securesnap.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-03-06 19:00:00 CET 5 days left Fri 2026-02-27 19:00:02 CET 1 day 22h ago securesnap.timer securesnap.service
And the service logs are displayed with this command:
~# journalctl -u securesnap.service
OnCalendar is an option in the Timer block of a Timer Unit file that specifies when the timer should be triggered. The syntax for OnCalendar is as follows:
OnCalendar=*-*-* 02:00:00
as an example for "Every day at 2 a.m."
systemd-analyze calendar is very useful as an analysis tool in Bash to correctly adopt the correct syntax for the OnCalendar timer option and to see if the desired time period works.
This is what it looks like, for example:
~# systemd-analyze calendar "Fri 19:00"
Original form: Fri 19:00
Normalized form: Fri *-*-* 19:00:00
Next elapse: Fri 2026-02-27 19:00:00 CET
(in UTC): Fri 2026-02-27 18:00:00 UTC
From now: 3 days left
Both the original form and the normalized form can be directly transferred to the timer.
Overall, the OnCalendar option offers a flexible and powerful way to schedule tasks in Linux using systemd timers. By understanding the syntax and using the appropriate calendar expressions, you can automate your system and save time and effort.