Timer-Ausdruecke praezise schreiben
Ein OnCalendar-Ausdruck sieht auf den ersten Blick nach einer simplen Datumsangabe aus, kann aber Wochentage, Bereiche, Listen und Wiederholungen in einer einzigen, kompakten Zeile kombinieren. Wer die Syntax nicht wirklich versteht, kopiert Beispiele aus dem Internet und wundert sich, warum der Timer nie oder zur falschen Zeit ausloest. Dieser Artikel erklaert die OnCalendar-Syntax systematisch, von einfachen Kurzformen bis zu komplexen Ausdruecken, und zeigt, wie man jeden Ausdruck vor dem Einsatz zuverlaessig mit systemd-analyze calendar testet.
Inhaltsverzeichnis
- 1. Warum die OnCalendar-Syntax eigene Aufmerksamkeit verdient
- 2. Aufbau eines OnCalendar-Ausdrucks im Detail
- 3. Wildcards, Listen und Bereiche in der Praxis
- 4. Wiederholungen mit Schraegstrich und Kurzformen
- 5. Persistent und RandomizedDelaySec richtig einsetzen
- 6. Ausdruecke testen mit systemd-analyze calendar
- 7. Zeitzonenverhalten von Timern verstehen
- 8. Praxisbeispiele fuer typische Betriebsszenarien
- 9. OnCalendar-Kurzformen im Vergleich zu Cron-Ausdruecken
- 10. Zusammenfassung
- 11. FAQ
1. Warum die OnCalendar-Syntax eigene Aufmerksamkeit verdient
Viele Administratoren wechseln von klassischem Cron zu systemd-Timern, uebernehmen dabei aber eine falsche Erwartungshaltung an die Syntax. Waehrend eine Crontab-Zeile fuenf feste Felder in einer festen Reihenfolge kennt, ist ein OnCalendar-Ausdruck eine deutlich flexiblere Notation, die Wochentag, Datum und Uhrzeit in einem einzigen, frei kombinierbaren String beschreibt. Genau diese Flexibilitaet ist der Grund, warum kleine Tippfehler in der OnCalendar-Syntax nicht immer sofort auffallen, sondern erst dann, wenn der Timer zur falschen Zeit oder gar nicht ausloest.
Die gute Nachricht: systemd liefert mit systemd-analyze calendar ein eingebautes Werkzeug, das jeden OnCalendar-Ausdruck sofort auswertet und die naechsten Ausfuehrungszeitpunkte anzeigt, ganz ohne den Timer tatsaechlich zu aktivieren. Wer diese Syntax einmal systematisch durchdringt, kann Cron-Wissen fast vollstaendig auf systemd uebertragen und gewinnt zusaetzlich Moeglichkeiten, die reines Cron gar nicht bietet, etwa Ausdruecke fuer den letzten Tag eines Monats oder fuer den zweiten Dienstag.
2. Aufbau eines OnCalendar-Ausdrucks im Detail
Ein vollstaendiger OnCalendar-Ausdruck folgt dem Muster Wochentag Jahr-Monat-Tag Stunde:Minute:Sekunde, wobei jeder dieser Teile optional weggelassen werden kann. Fehlt der Wochentag, gilt der Ausdruck fuer jeden Wochentag. Fehlt die Uhrzeit, wird implizit Mitternacht angenommen. Der Ausdruck Mon 2026-08-03 09:00:00 beschreibt damit einen einzelnen, exakten Zeitpunkt, waehrend *-*-* 03:00:00 jeden Tag um drei Uhr morgens bedeutet, unabhaengig vom Wochentag.
Der Stern * steht dabei fuer jeden moeglichen Wert an dieser Position, analog zum Wildcard in Cron, aber mit dem Unterschied, dass die OnCalendar-Syntax auch Jahr, Monat und Tag getrennt als Wildcard behandeln kann. Diese Granularitaet erlaubt Ausdruecke wie 2026-*-01 fuer den ersten Tag jedes Monats im Jahr 2026, was mit klassischem Cron nur ueber Umwege oder zusaetzliche Skript-Logik moeglich waere.
# backup.timer — a minimal systemd timer unit
[Unit]
Description=Nightly backup timer
[Timer]
# Fixed calendar expression: every day at 03:00:00
OnCalendar=*-*-* 03:00:00
Unit=backup.service
[Install]
WantedBy=timers.target
3. Wildcards, Listen und Bereiche in der Praxis
Neben dem einfachen Wildcard unterstuetzt die OnCalendar-Syntax auch Listen und Bereiche. Eine Liste wird mit Kommas geschrieben, etwa Mon,Wed,Fri fuer Montag, Mittwoch und Freitag. Ein Bereich nutzt zwei Punkte, etwa Mon..Fri fuer alle Werktage von Montag bis Freitag. Beide Notationen lassen sich kombinieren, sodass Mon..Fri 08,12,17:00:00 dreimal taeglich an jedem Werktag ausloest, um acht, zwoelf und siebzehn Uhr.
Fuer Kalendertage funktioniert dieselbe Logik: 01,15 *-*-* 06:00:00 triggert am ersten und fuenfzehnten Tag jedes Monats um sechs Uhr, waehrend *-01,04,07,10-01 den ersten Tag jedes Quartalsmonats beschreibt. Diese Kombinierbarkeit von Listen und Bereichen macht OnCalendar-Ausdruecke gegenueber Cron-Zeilen deutlich lesbarer, sobald man einmal die Grundmuster verinnerlicht hat, weil man nicht mehr zaehlen muss, in welcher Spalte welcher Wert steht.
[Timer]
# Weekdays only, three times a day
OnCalendar=Mon..Fri 08,12,17:00:00
[Timer]
# First and fifteenth of every month at 06:00
OnCalendar=01,15 *-*-* 06:00:00
[Timer]
# Last day of every month — systemd resolves this automatically
OnCalendar=*-*~1 23:59:00
4. Wiederholungen mit Schraegstrich und Kurzformen
Fuer regelmaessige Intervalle innerhalb eines Feldes gibt es den Schraegstrich-Operator, etwa *-*-* 0/4:00:00 fuer alle vier Stunden beginnend um Mitternacht. Das ist besonders praktisch fuer Monitoring- oder Health-Check-Jobs, die in festen Abstaenden laufen sollen, ohne dass man jede einzelne Stunde als Liste ausschreiben muss. Wichtig dabei: Der Schraegstrich definiert das Intervall relativ zum davor stehenden Startwert, nicht relativ zur aktuellen Uhrzeit beim Aktivieren des Timers.
Fuer die haeufigsten Faelle bietet systemd zusaetzlich fertige Kurzformen wie hourly, daily, weekly, monthly, yearly und quarterly. Diese Kurzformen sind reine Aliase, die intern in einen vollen OnCalendar-Ausdruck aufgeloest werden, etwa daily zu *-*-* 00:00:00. Fuer einfache, taegliche oder woechentliche Jobs ohne besondere Uhrzeit sind diese Kurzformen die lesbarste und am wenigsten fehleranfaellige Wahl.
[Timer]
# Every 4 hours, using the slash repeat operator
OnCalendar=*-*-* 0/4:00:00
[Timer]
# Equivalent using a built-in shorthand (less flexible, but readable)
OnCalendar=daily
[Timer]
# Every 15 minutes, via slash operator on minutes
OnCalendar=*-*-* *:0/15:00
5. Persistent und RandomizedDelaySec richtig einsetzen
Zwei Optionen in der [Timer]-Sektion sind fuer den Produktivbetrieb besonders wichtig, werden aber haeufig uebersehen. Persistent=true sorgt dafuer, dass ein verpasster Lauf, etwa weil der Server zum geplanten Zeitpunkt ausgeschaltet war, beim naechsten Boot sofort nachgeholt wird. Ohne diese Option geht ein verpasster Timer-Lauf einfach verloren, was besonders bei Laptops und selten laufenden Servern zu unbemerkt fehlenden Backups oder Wartungsjobs fuehren kann.
RandomizedDelaySec verzoegert den tatsaechlichen Start um einen zufaelligen Wert innerhalb des angegebenen Fensters, was bei vielen gleichzeitig geplanten Timern auf unterschiedlichen Servern verhindert, dass alle exakt zur selben Sekunde starten und dadurch Lastspitzen auf gemeinsam genutzten Ressourcen wie Datenbanken oder Netzwerkspeicher erzeugen. Beide Optionen zusammen machen aus einem simplen OnCalendar-Ausdruck eine robuste, produktionsreife Scheduling-Loesung.
[Timer]
OnCalendar=daily
# Catch up on missed runs after being offline (e.g. laptop suspended overnight)
Persistent=true
# Spread the actual start time within a 10 minute window to avoid load spikes
RandomizedDelaySec=600
6. Ausdruecke testen mit systemd-analyze calendar
Bevor ein neuer Timer scharf geschaltet wird, sollte jeder OnCalendar-Ausdruck mit systemd-analyze calendar geprueft werden. Der Befehl zeigt neben der naechsten Ausfuehrungszeit auch an, ob der Ausdruck syntaktisch gueltig ist, und normalisiert ihn in seine kanonische Form. Diese Normalisierung ist ein unterschaetztes Diagnosewerkzeug, weil sie sofort sichtbar macht, ob ein Ausdruck tatsaechlich das bedeutet, was man beabsichtigt hat.
Mit der Option --iterations lassen sich zudem mehrere zukuenftige Ausfuehrungszeitpunkte gleichzeitig ausgeben, was besonders bei komplexen Ausdruecken mit Wochentagen und Bereichen hilft, das tatsaechliche Muster ueber mehrere Wochen zu ueberpruefen, bevor der Timer produktiv geht. Diese Vorabpruefung spart in der Praxis erhebliche Zeit gegenueber dem Ansatz, einen Timer scharf zu schalten und dann tagelang zu beobachten, ob er zum erwarteten Zeitpunkt ausloest.
# Validate a calendar expression and see the next execution time
systemd-analyze calendar "Mon..Fri 08,12,17:00:00"
# Show multiple future occurrences to verify the pattern over weeks
systemd-analyze calendar --iterations=5 "01,15 *-*-* 06:00:00"
# Confirm which timers are actually scheduled next on this system
systemctl list-timers --all
7. Zeitzonenverhalten von Timern verstehen
OnCalendar-Ausdruecke werden standardmaessig in der lokalen Zeitzone des Systems interpretiert, nicht in UTC. Das ist praktisch, solange Server und Anwendungsfaelle in derselben Zeitzone bleiben, wird aber zur Falle bei der Sommerzeit-Umstellung: Ein taeglicher Timer um 02:30:00 kann an dem Tag, an dem die Uhr vorgestellt wird, ausfallen, weil diese Uhrzeit an diesem Tag schlicht nicht existiert. Umgekehrt kann er beim Zurueckstellen der Uhr doppelt ausloesen.
Fuer zeitkritische Server-Jobs, insbesondere solche mit Bezug zu verteilten Systemen oder internationalen Deployments, empfiehlt es sich deshalb, den Zeitpunkt bewusst ausserhalb des Sommerzeit-Umstellungsfensters zu legen, etwa auf 03:30 statt 02:30 Uhr, oder das System konsequent auf UTC zu betreiben und die lokale Interpretation komplett zu vermeiden. Serverbetriebssysteme profitieren fast immer davon, grundsaetzlich in UTC zu laufen und Zeitzonenumrechnung ausschliesslich der Anwendungsebene zu ueberlassen.
8. Praxisbeispiele fuer typische Betriebsszenarien
Ein klassisches Wartungsfenster fuer nachts laufende Backups laesst sich mit OnCalendar=*-*-* 02:00:00 kombiniert mit Persistent=true abbilden, damit ein verpasster Lauf am naechsten Boot nachgeholt wird. Fuer monatliche Abrechnungslaeufe eignet sich OnCalendar=*-*~1 04:00:00, was zuverlaessig den letzten Tag jedes Monats trifft, unabhaengig davon, ob der Monat 28, 30 oder 31 Tage hat, ein Detail, das mit klassischem Cron zusaetzliche Skript-Logik erfordern wuerde.
Fuer Log-Rotation am Ende jeder Arbeitswoche eignet sich OnCalendar=Fri 18:00:00, waehrend ein Health-Check-Job mit hoher Frequenz ueber OnCalendar=*:0/5 alle fuenf Minuten laeuft. Diese Beispiele zeigen, wie sich reale Betriebsanforderungen fast immer direkt in einen einzigen, kompakten OnCalendar-Ausdruck uebersetzen lassen, ohne zusaetzliche Wrapper-Skripte fuer die Zeitlogik zu benoetigen.
9. OnCalendar-Kurzformen im Vergleich zu Cron-Ausdruecken
Wer von Cron kommt, profitiert von einer direkten Gegenueberstellung, um die neue Syntax schneller zu verinnerlichen und typische Uebersetzungsfehler zu vermeiden.
| Anforderung | Cron-Ausdruck | OnCalendar-Ausdruck |
|---|---|---|
| Taeglich um 3 Uhr | 0 3 * * * |
*-*-* 03:00:00 |
| Werktags um 8, 12, 17 Uhr | 0 8,12,17 * * 1-5 |
Mon..Fri 08,12,17:00:00 |
| Alle 15 Minuten | */15 * * * * |
*-*-* *:0/15:00 |
| Letzter Tag im Monat | Nicht direkt moeglich | *-*~1 23:59:00 |
| Verpasste Laeufe nachholen | Nicht ohne anacron | Persistent=true |
Der Hauptvorteil der OnCalendar-Syntax liegt genau in den Zeilen, die Cron nicht oder nur mit Zusatzwerkzeugen abbilden kann: Monatsende, Nachholen verpasster Laeufe und Jitter-Verteilung sind in systemd nativ eingebaut, waehrend sie in reinen Cron-Umgebungen zusaetzliche Skript-Logik oder Hilfsprogramme wie anacron erfordern.
Mironsoft
Linux-Server-Administration und Scheduling-Infrastruktur
Cron-Jobs sauber auf systemd-Timer migrieren?
Wir analysieren eure bestehenden Cronjobs, uebersetzen sie in robuste OnCalendar-Ausdruecke mit Persistent und RandomizedDelaySec und richten Monitoring fuer eure Timer-Units ein.
Migration
Crontab-Zeilen in getestete OnCalendar-Ausdruecke uebersetzen
Haertung
Persistent, RandomizedDelaySec und Fehlerbehandlung nachruesten
Monitoring
Fehlgeschlagene und verpasste Timer-Laeufe zuverlaessig erkennen
10. Zusammenfassung
Die OnCalendar-Syntax beschreibt Wochentag, Datum und Uhrzeit in einem einzigen, flexiblen Ausdruck und ersetzt damit die fuenf starren Spalten einer Crontab-Zeile durch eine deutlich maechtigere Notation. Listen mit Kommas, Bereiche mit zwei Punkten und Wiederholungen mit Schraegstrich lassen sich beliebig kombinieren, waehrend Kurzformen wie daily oder weekly die haeufigsten Faelle abkuerzen. systemd-analyze calendar ist das zentrale Werkzeug, um jeden Ausdruck vor dem produktiven Einsatz zu validieren.
Persistent=true holt verpasste Laeufe nach dem naechsten Boot nach, RandomizedDelaySec verteilt gleichzeitig geplante Timer ueber ein Zeitfenster und verhindert Lastspitzen. Faelle wie der letzte Tag eines Monats, die in reinem Cron zusaetzliche Skript-Logik erfordern, sind in der OnCalendar-Syntax nativ eingebaut. Wer die Grundmuster einmal verinnerlicht hat, schreibt Timer-Ausdruecke schneller und fehlerfreier als aequivalente Cron-Zeilen.
systemd OnCalendar-Syntax, das Wichtigste auf einen Blick
Grundstruktur
Wochentag Jahr-Monat-Tag Stunde:Minute:Sekunde, jeder Teil optional weglassbar oder als Wildcard *.
Listen und Bereiche
Kommas fuer Listen (Mon,Wed,Fri), zwei Punkte fuer Bereiche (Mon..Fri), Schraegstrich fuer Intervalle.
Vor Einsatz testen
systemd-analyze calendar "Ausdruck" zeigt naechste Ausfuehrung und normalisierte Form.
Persistent und Jitter
Persistent=true holt verpasste Laeufe nach, RandomizedDelaySec verhindert Lastspitzen.