If you are using crontab then you are familiar with starting actions depending on the date or time.
I have posted earlier why I stopped using crontab and have replaced it with the systemd command especially for jobs that should start at boot and that must restart automatically in case of a crash.
But just like crontab, systemd also provides the ability to schedule tasks at fixed times and dates.
In this article, I would like to show you how to apply the chronometric logic to the systemd command and to start timed actions like e.g. on the hour every hour/day/week/month or even on specific dates at a specific time.
I will focus on the commands and options that you would typically use for a digital picture frame application and spare you every detail and option so that you can quickly implement what you are looking for.
The simple way to schedule intervals in systemd without a timer
I want to start with an example where you don’t actually need a separate systemd timer.
If you have e.g. a Python script which sends a status message every ten minutes, there is no need for a timer. Just add these lines in your [Service] part of your .service script.
Restart=always
RestartSec=600
The number in RestartSec specifies in seconds how long to wait until a restart is triggered after the script has been executed. This syntax is useful when it really doesn’t matter if the message is sent at 0:10, 0:20, 0:30, etc. but just with an interval of 10 minutes, whenever it starts after boot.
Using realtime timers
The situation is different should you want a task scheduling at a specific time, like the chime of the hour bell.
In this case, you set up your systemd .service file as you normally would AND add a timer counterpart with the same name to it. The .timer file activates and controls the .service file.
The systemd command knows two types of timers: relative (called “monotonic”) and absolute (called “realtime”) timers.
Relative timers are defined by the time of another event like e.g. an event happening relative to the boot time (e.g. 10 minutes after boot).
Much more often, however, are realtime use cases for scheduling in “absolute” terms. This is similar to crontab.
To create a timer type
sudo nano /etc/systemd/system/name-of-your-timer.timer
It is vital that this file resides in the same directory and has the same name as your corresponding .service file.
The structure of a timer file is very similar to that of a service file but instead of a Service unit, there is the timer unit.
[Unit]
Description=Run my script every hour
[Timer]
OnCalendar=hourly
[Install]
WantedBy=timers.target
Under [Unit], you give a name that would help you recognise your timer in an overview list of timer files.
[Timer] has the following options that is important in our case:
OnCalendar=hourly
Specifying “hourly” means that the task is triggered each hour at :00.
dailytriggers at 00:00:00.weeklyon Monday at 00:00:00monthlywill be executed on the first day of each month at 00:00:00
But it gets much better and the advantage compared to crontab is that your timer encoding is written in plain English and you don’t need a crontab ruler to translate.
There are other options like AccuracySec= but the default is one minute and that shall be fine for digital picture frames.
Timer syntax logic
The OnCalendar event uses the following syntax:
OnCalendar=DayOfWeek Year-Month-Day Hour:Minute:Second
An asterisk can be used to specify any value, so *-05-01 means the first of May in any year and *-*-* means every day.
Commas may be used to list possible values (e.g. Mon, Wed).
Two values separated by .. indicate a contiguous range (e.g. Mo..Fr).
To run a service at different times, OnCalendar can be specified more than once, like
OnCalendar=Mon..Fri 07:00
OnCalendar=Sat,Sun 09:00
To read more about the timer syntax, I recommend this page.
OnCalendar systemd timer examples
If you want to trigger a task every Friday at 18h, just say
OnCalendar=Fri 18:00:00
The weekdays must be in English and you can either use the three letter abbreviated form or the long version.
To trigger a task every five minutes starting at 00:00
OnCalendar=*:0/5
The asterisk means every day, every five minutes starting from the minute 0.
To set “turn on” times for your digital picture frame during weekdays, you could use
OnCalendar=Mon..Fri 07:00:00
This task will then be executed at 7 o’ clock in the morning from Monday to Friday.
And if you want to go wild, and define a certain image playlist or directory for your wedding anniversary every year (so you don’t forget it), you can create a timer that is triggered only once a year, like
OnCalendar=*-05-01 06:00:00
This schedules a task on May 1 of every year, at 6am. Note the exact shape: two digits for the month and the day, a space and not a comma between the date and the time. systemd is fussy about it, and systemd-analyze calendar "*-05-01 06:00:00" will tell you whether it has understood what you meant and when it will next fire.
You can make all kinds of combinations and exception much more flexibly than you ever could with crontab.
Useful timer commands
List all timers
To list all active timers on your Raspberry Pi system type
systemctl list-timers
If you add the --all option at the end, you will see a list of all timers, active or not, which is helpful for debugging.

The output shows you
- NEXT: The next time the timer will run
- LEFT: How many times before the next time timer will run again
- LAST: The last time the timer ran
- PASSED: How much time has passed since the last time the timer ran
- UNIT: The timer unit in which the schedule is set
- ACTIVATES: The service unit activated by the timer
Activate a timer now
Activating a timer ad hoc is done with
$ sudo systemctl start <timer-unit-name>.timer
To have a timer automatically activated at boot, make sure it has an [Install] paragraph, where you specify when the activation should happen, like e.g., WantedBy=timers.target.
Stopping a timer now
To stop it again, type
$ sudo systemctl stop <timer-unit-name>.timer
Automatically start at boot
To automatically start a timer when booting use
$ sudo systemctl enable <timer-unit-name>.timer
and disable to remove this autostart again.
Only enable and start the timer unit, not the service unit.
Whenever you edit the unit files enter
$ sudo systemctl daemon-reload
Check the timer status
Of course, there is also a status check with
$ sudo systemctl status <timer-unit-name>.timer
which shows you exactly when the timer will trigger next.

Example .service and .timer combination to turn your frame on/off at fixed times
One of the simplest use cases for a timer is a script that turns your frame on in the morning and off when you go to sleep. And as workdays are different from weekends, you need to specify that, too.
This example needed rewriting in 2026, and it is worth saying why. The command this article used to give, vcgencmd display_power 1 and 0, was retired when the Raspberry Pi desktop moved to Wayland and does not work on any current Raspberry Pi OS. What replaced it depends on which frame you have built:
- On picframe3 (Pi 4 or Pi 5, Raspberry Pi OS Lite), the frame switches the panel itself and takes the instruction over its own local API. That is the example below. Before you build it, though: picframe3 already has a screen-off schedule of its own,
power.schedule, on the settings page under “when the screen turns off”. A timer is only worth writing for something that schedule cannot express. - On a pi3d PictureFrame on the Raspberry Pi OS desktop, it is
wlr-randr, described in The new way to turn your connected HDMI monitor on and off. That one is awkward from a system-wide timer, becausewlr-randrhas to reach the Wayland session that owns the screen. If you go that way, a user timer undersystemctl --useris the sane place for it. I have not re-tested that combination, so treat it as a direction rather than a recipe.
There was also a plain mistake in the old service file here, worth knowing about because it is a common one: ExecStart=sudo vcgencmd display_power 1. ExecStart needs an absolute path to the program, and sudo does not belong in a unit file at all — there is no terminal to ask for a password and systemd already decides which user the command runs as.
Let’s build a .service file which turns it on:
Create a new file with
sudo nano /etc/systemd/system/turn_monitor_on.service
Copy & paste
[Unit]
Description=Turns the monitor on
[Service]
Type=oneshot
User=pi
ExecStart=/usr/bin/curl -fsS -X POST -H "Content-Type: application/json" -d '{"action": "display_on"}' http://localhost:9000/api/command
[Install]
WantedBy=multi-user.target
Put your own user name in User=; there has been no default pi user on Raspberry Pi OS since 2022. For the evening counterpart, the only change is display_off in place of display_on. Type=oneshot is right here because the command finishes immediately rather than staying resident.
and save the file with CTRL+O and close the editor with with CTRL+X.
Create the corresponding .timer file with
sudo nano /etc/systemd/system/turn_monitor_on.timer
Copy & paste
[Unit]
Description=Timer to turn the monitor on
[Timer]
OnCalendar=Mon..Fri 07:00
OnCalendar=Sat,Sun 09:00
[Install]
WantedBy=timers.target
and save the file with CTRL+O and close the editor with with CTRL+X.
We need to change the file permissions to make the files readable by all by typing
sudo chmod 644 /etc/systemd/system/turn_monitor_on.service
Tell the system that you have added this file and want to enable this service so that it starts at boot.
sudo systemctl daemon-reload
sudo systemctl enable turn_monitor_on.timer
Do not enable the service file because that would mean to start the service at boot time independent of any timer settings.
Now create almost the same service and timer for turning the screen off at night.
Reboot your Pi, and you are all set!
To check if everything is ok, type
systemctl list-timers
Conclusion
The timer command of systemd gives you plenty of flexibility to schedule events very precisely by date or time. Although it is a bit more complex than crontab, it provides plenty of variations that can be specified and verified in (more or less) plain English.
That’s why I have abandoned good old crontab, which has served me loyally over all these years in favor of the younger systemd services and timer. Please don’t make me feel bad. It’s only software!
Was this article helpful?
Thank you for your support and motivation.