Workflows & Testing
POSIX-CronIANA-TimezonesSystemd-TimerGitHub-ActionsOffline-PWA

Cron- & Zeitzonen-Prüfstand – Zeitpläne auf Deutsch verstehen, Sommerzeit-Fallen prüfen und exportieren

Interaktiver Cron-Prüfstand im Browser: 5-Felder-Syntax auf Deutsch erklären, UTC- und Sommerzeit-Fallen erkennen sowie Systemd- und GitHub-Timer erzeugen.

LKLukas Kopischke
Zuletzt aktualisiert am
Cron- & Zeitzonen-PrüfstandZeitzonen-Sicher · 100 % Lokal
Typische Zeitpläne & Fallen:
Klartext-Bedeutung

„Um 08:15 Uhr, montags bis freitags.“

Minute0–59
Stunde0–23
Tag (Monat)1–31
Monat1–12
Wochentag0–6 (So–Sa)
Nächste 10 Ausführungen
#Lokalzeit (Europe/Berlin)UTC-GegenstückAbstand
1
Di., 27.10.2026, 08:15 MEZ
27.10., 07:15 UTCin 15 Min.
2
Mi., 28.10.2026, 08:15 MEZ
28.10., 07:15 UTCin 1 Tg. 0 Std.
3
Do., 29.10.2026, 08:15 MEZ
29.10., 07:15 UTCin 2 Tg. 0 Std.
4
Fr., 30.10.2026, 08:15 MEZ
30.10., 07:15 UTCin 3 Tg. 0 Std.
5
Mo., 02.11.2026, 08:15 MEZ
02.11., 07:15 UTCin 6 Tg. 0 Std.
6
Di., 03.11.2026, 08:15 MEZ
03.11., 07:15 UTCin 7 Tg. 0 Std.
7
Mi., 04.11.2026, 08:15 MEZ
04.11., 07:15 UTCin 8 Tg. 0 Std.
8
Do., 05.11.2026, 08:15 MEZ
05.11., 07:15 UTCin 9 Tg. 0 Std.
9
Fr., 06.11.2026, 08:15 MEZ
06.11., 07:15 UTCin 10 Tg. 0 Std.
10
Mo., 09.11.2026, 08:15 MEZ
09.11., 07:15 UTCin 13 Tg. 0 Std.
Einsatzfertiger Export
# /etc/crontab oder crontab -e (Zeitzone prüfen: CRON_TZ=Europe/Berlin)
CRON_TZ=Europe/Berlin
# flock verhindert überlappende Prozesse, falls der vorherige Lauf noch hängt:
15 8 * * 1-5 /usr/bin/flock -n /tmp/mein-job.lock /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
Alle Berechnungen laufen lokal im Browser – ohne Werbung oder Account-Zwang.

Ein nächtliches Datenbank-Backup steht auf 30 2 * * * – und am letzten Sonntag im März existiert kein einziges Backup-Archiv, während das Skript Ende Oktober zweimal hintereinander anläuft. Oder du trägst 0 9 13 * 5 ein, um einen Prüfjob nur an einem „Freitag, dem 13.“ zu starten, wunderst dich aber, warum er plötzlich jeden einzelnen Freitag im Jahr feuert.

Ein klassischer vergleicht jede volle Minute fünf Felder (Minute, Stunde, Monatstag, Monat, Wochentag) mit der lokalen Systemuhr. Weil Monatstag und Wochentag laut Spezifikation per logischem ODER verknüpft sind und Cloud-Plattformen wie GitHub Actions strikt in UTC rechnen, entstehen ohne Zeitzonen-Prüfung stille Ausfälle. Zudem holt klassisches Cron verpasste Läufe nach einem Server-Neustart nicht nach – hierfür sind systemd-Timer mit Persistent=true die robustere Wahl.

Merksatz

Prüfe jeden Cron-Ausdruck immer gemeinsam mit seiner Ziel-Zeitzone: Cloud-Runner rechnen fast immer in UTC, lokale Linux-Server stolpern zwischen 02:00 und 02:59 Uhr über die Zeitumstellung, und gesetzter Monatstag plus Wochentag wirken als ODER statt UND.

Wie wertet Cron seine fünf Felder aus – und wo lauern die drei teuersten Denkfehler?

Jede Zeile einer Crontab beginnt mit fünf durch Leerzeichen getrennten Zeitfeldern:

  1. Minute (0–59): Zu welcher Minute der Stunde soll der Befehl starten? (*/15 entspricht 0, 15, 30, 45).
  2. Stunde (0–23): In welcher Stunde des Tages (24-Stunden-Zählung)?
  3. Tag im Monat (1–31): An welchem Kalendertag?
  4. Monat (1–12 oder JAN–DEC): In welchem Monat?
  5. Wochentag (0–6 bzw. 7): An welchem Wochentag (0 und 7 stehen beide für Sonntag)?

In der Praxis sorgen drei Eigenheiten dieses Modells regelmäßig für Produktionsfehler:

1. Die POSIX-ODER-Regel zwischen Monatstag und Wochentag

Solange eines der beiden Tagesfelder auf * steht, verhält sich Cron erwartungsgemäß (15 8 * * 1-5 läuft montags bis freitags um 08:15 Uhr). Sobald jedoch beide Felder vom Sternchen abweichen – etwa 0 9 13 * 5 –, bildet der Standard die Vereinigungsmenge (ODER): Der Job startet am 13. jedes Monats sowie an jedem Freitag. Willst du wirklich eine UND-Bedingung (z. B. „erster Montag im Monat“ für 0 9 1-7 * 1), setzt du in der Crontab nur das Datumsfenster 1-7 und prüfst den Wochentag im Aufrufbefehl.

2. Sommer- und Winterzeit (02:00 bis 02:59 Uhr)

Läuft dein Server in einer Zeitzone mit Sommerzeitumstellung wie , springt die Uhr am letzten März-Sonntag um 02:00 direkt auf 03:00 vor: Ein auf 30 2 * * * geplanter Job fällt an diesem Tag ersatzlos aus. Am letzten Oktober-Sonntag springt die Uhr von 03:00 auf 02:00 zurück – naive Cron-Implementierungen ohne Sonderbehandlung führen Jobs in dieser Stunde doppelt aus.

3. Überlappende Prozesse ohne Sperrdatei (flock)

Cron startet Kommandos blind nach Uhrzeit und prüft nicht, ob der vorherige Lauf desselben Skripts noch arbeitet. Hängt ein */5 * * * *-Import wegen einer langsamen Gegenstelle für 20 Minuten, laufen nach einer Viertelstunde vier identische Prozesse parallel und blockieren Datenbank oder Arbeitsspeicher. Unter Linux schützt das Dienstprogramm flock zuverlässig vor solchen Kaskaden:

BASH
# Sichere Produktions-Crontab: explizite Zeitzone + nicht-blockierende Sperrdatei (flock -n)
CRON_TZ=Europe/Berlin
# Läuft täglich um 03:15 Uhr (außerhalb des 02:xx-Zeitumstellungsfensters!)
15 3 * * * /usr/bin/flock -n /run/lock/nightly-backup.lock /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# Echte UND-Verknüpfung für „nur am ersten Montag des Monats um 08:00 Uhr“:
# Cron prüft die Tage 1..7, test(1) prüft zusätzlich Wochentag 1 (Montag)
0 8 1-7 * * [ "$(date +\%u)" = "1" ] && /usr/local/bin/monthly-report.sh

Beachte das maskierte Prozentzeichen \% im date-Aufruf: In einer Crontab interpretiert der Daemon jedes unmaskierte % als Zeilenumbruch für die Standardeingabe (stdin) – einer der häufigsten Syntaxfehler in Shell-Einzeilern.

Welcher Zeitgeber passt zu welchem Einsatz – Crontab, Systemd-Timer oder GitHub Actions?

Plattform / DienstStandard-ZeitzoneVerpasste Läufe nach Ausfall?ÜberlappungsschutzTypischer Einsatz & wichtige Grenze
Klassische Linux crontabLokale Server-ZeitzoneNein (Ausfallzeit = Job entfällt)Manuell über flock -n nötigSchnell eingerichtet auf jedem Unix-System; kein eingebautes Logging pro Lauf
systemd.timer (OnCalendar=)Lokale Server-Zeitzone (oder UTC)Ja, mit Persistent=true sofort nach RebootAutomatisch (Service-Unit läuft nicht doppelt)Erste Wahl auf modernen Linux-Servern und Laptops; etwas mehr Konfigurationsdateien (.timer + .service)
GitHub Actions (on.schedule)Immer zwingend UTCNeinÜber concurrency: konfigurierbarKein eigener Server nötig; bei hoher Plattformlast sind Verzögerungen von 5 bis 20 Minuten normal, Mindestintervall beträgt 5 Minuten
Robuste Zeitplanung im Betrieb
  • Nächtliche Wartungsfenster in Europe/Berlin auf 01:xx oder 03:xx / 04:xx Uhr legen, um die 02:00-Uhr-Umstellungsstunde komplett zu meiden
  • Wiederkehrende Skripte immer idempotent schreiben und mit flock -n oder systemd-Units gegen parallele Doppelstarts verriegeln
  • Bei GitHub Actions zusätzlich workflow_dispatch: aktivieren, damit sich der Job im Ernstfall jederzeit per Klick ohne Wartezeit starten lässt
Typische Produktionsfallen
  • Keine minutengenauen Echtzeit-Anforderungen auf GitHub Actions schedule stützen – der Queue-Verzug auf öffentlichen Runnern schwankt spürbar
  • Keine ungeschützten %-Zeichen (wie date +%F) ohne Backslash \% direkt in eine Crontab-Zeile schreiben
  • Nicht alle Jobs einer Server-Flotte exakt auf 0 0 * * * (Mitternacht Punkt null) bündeln – das erzeugt künstliche Lastspitzen („Thundering Herd“)
Warum krumme Minuten wie 17 3 * * * APIs entlasten

Millionen automatisierter Systeme weltweit feuern exakt zur vollen Stunde (0 * * * *) oder um Mitternacht (0 0 * * *). Wählst du für unkritische Abfragen bewusst eine krumme Minute wie 17 3 * * * oder ergänzt bei systemd RandomizedDelaySec=45s, umgehst du fremde Rate-Limits und überlastete Gegenstellen.

Prüfpunkte vor dem Aktivieren eines neuen Cronjobs

  • Zeitzone des Zielsystems verifizieren: Prüfe per timedatectl (Linux) bzw. in der Plattform-Doku, ob der Scheduler in Europe/Berlin oder UTC rechnet.
  • März- und Oktober-Sprung gegenprüfen: Stelle im obigen Prüfstand den Zeit-Anker testweise auf März-Sommerzeit und Oktober-Winterzeit, um Ausfälle oder Doppelläufe auszuschließen.
  • Umgebungsvariablen (PATH) explizit setzen: Cron startet mit minimalem PATH=/usr/bin:/bin – verwende absolute Binärpfade wie /usr/local/bin/node, damit Skripte nicht trotz erfolgreichem Handtest im Terminal scheitern.
  • Fehlerausgabe sichtbar machen: Leite stderr (2>&1) in ein rotiertes Logfile um oder prüfe den Status bei systemd über journalctl -u mein-job.service.

Quellen und nächste Schritte