SSD Nodes Learn 🎉 VPS ab $5.50/Monat
Anleitungen Matt ConnorVon Matt Connor

n8n Zeitzone richtig setzen: Schedule Trigger korrigieren

n8n verwendet drei Zeitzonen: TZ, GENERIC_TIMEZONE und die Workflow-Zone. Prüfen Sie die Standardzone America/New_York, sonst laufen Trigger zeitversetzt.

Warum Ihr n8n-Zeitplan-Trigger zur falschen Uhrzeit ausgelöst wird

Ein n8n-Zeitplan-Trigger wird zur falschen Uhrzeit ausgelöst, weil n8n die Zeitzone aus drei verschiedenen Quellen liest. Wenn Sie nur eine davon korrigieren, beheben Sie nur einen Teil des Problems. Die drei Quellen sind die Variable TZ des Containers, der Standardwert GENERIC_TIMEZONE der Instanz und eine Zeitzone, die innerhalb eines einzelnen Workflows festgelegt wurde. Setzen Sie alle drei Werte einmal. Danach wird jeder neu erstellte Zeitplan zur erwarteten Uhrzeit ausgeführt.

Prüfen Sie zuerst eine naheliegende Annahme. Ein frisch eingerichtetes selbst gehostetes n8n plant nicht in UTC (koordinierte Weltzeit). Die Uhr des Containers läuft in UTC, weil das offizielle Image keine Variable TZ setzt. Die Zeitplanung ist davon unabhängig. Der dokumentierte Standardwert von n8n für GENERIC_TIMEZONE ist America/New_York (Stand August 2026). Daher führt eine unveränderte Instanz ihre Schedule Triggers nach der New-York-Zeit aus. Deshalb entspricht die gemeldete Abweichung selten dem tatsächlichen Abstand des jeweiligen Standorts zu UTC. Ein Betreiber in Berlin, der 06:00 Uhr festlegt, erhält eine Ausführung um 12:00 Uhr Ortszeit und um 11:00 Uhr während der Wochen im März, in denen die Vereinigten Staaten bereits auf Sommerzeit umgestellt haben, Europa jedoch noch nicht.

Die drei Zeitzonenebenen und welche davon Vorrang hat

TZ ist die Zeitzone des Betriebssystems innerhalb des Containers. Die n8n-Dokumentation beschreibt sie als Variable, die die Systemzeitzone festlegt und steuert, was Skripte und Befehle wie date zurückgeben. Sie bestimmt, was date innerhalb des Containers ausgibt, welcher Zeitstempel in einer Container-Logzeile steht, was new Date() in einem Code-Node zurückgibt und welche Zeitzone jedes dort ausgeführte Shell-Skript erkennt. Sie hat keinen Einfluss darauf, wann ein Schedule Trigger ausgelöst wird.

GENERIC_TIMEZONE ist die Zeitzone der n8n-Instanz. Die Dokumentation bezeichnet sie als Zeitzone der n8n-Instanz und weist darauf hin, dass sie für Schedule-Nodes wie Cron wichtig ist. Cron bezeichnet hier die standardisierte Syntax für zeitbasierte Zeitpläne. n8n stellt sie als Option Custom (Cron) im Schedule Trigger bereit.

Die Workflow-Zeitzone wird pro Workflow festgelegt. Öffnen Sie den Workflow auf der Arbeitsfläche, wählen Sie oben rechts die drei Punkte und anschließend Settings aus. Ändern Sie dann den Wert Timezone. Dadurch wird GENERIC_TIMEZONE für diesen Workflow überschrieben.

Für einen Schedule Trigger ist die Reihenfolge festgelegt. n8n verwendet die Workflow-Zeitzone, sofern für den Workflow eine festgelegt ist. Andernfalls verwendet n8n die Instanzzeitzone aus GENERIC_TIMEZONE. Ist auch diese nicht festgelegt, wird der integrierte Standardwert America/New_York verwendet. TZ wird bei keiner Stufe dieser Entscheidung berücksichtigt.

Bei Datumsangaben innerhalb Ihrer Nodes hängt die Antwort davon ab, welche Uhr die Abfrage verwendet. Luxon, die Bibliothek für Datumsangaben hinter n8n-Ausdrücken, verwendet die n8n-Zeitzone. Daher folgen $now und $today derselben Reihenfolge aus Workflow- und Instanzzeitzone wie der Trigger. Reines JavaScript new Date() in einem Code-Node fragt das Betriebssystem ab und folgt daher TZ. Diese Aufteilung verursacht den größten Teil der Verwirrung: Der Trigger kann korrekt sein, während jeder vom Workflow geschriebene Zeitstempel um mehrere Stunden abweicht.

Alle drei Werte in der Compose-Datei setzen

Setzen Sie TZ und GENERIC_TIMEZONE in der Datei direkt nebeneinander. So wird nicht versehentlich nur einer der beiden Werte gesetzt. Das folgende Fragment zeigt den für die Zeitzone relevanten Teil eines funktionierenden Dienstes. Der übrige Teil der Datei, der Reverse Proxy und das Zertifikat stammen aus einem selbst gehosteten n8n auf einem VPS hinter HTTPS.

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - GENERIC_TIMEZONE=Europe/Berlin
      - TZ=Europe/Berlin
      - N8N_RUNNERS_ENABLED=true
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

Wenden Sie die Änderung mit docker compose up -d an, nicht mit docker compose restart. Ein Neustart startet denselben Container erneut mit der Umgebung, mit der er erstellt wurde. Die Änderungen an der Datei werden dadurch nicht übernommen, und der laufende Prozess verwendet weiterhin die alte Umgebung. up -d erkennt die geänderte Umgebung und erstellt den Container neu. Wenn Sie diese Werte statt direkt in der Compose-Datei in einer env-Datei speichern, gilt dieselbe Regel für die Neuerstellung. Der Leitfaden Compose-env-Dateien und der Umgang mit Secrets erklärt, von welcher Stelle diese Datei eingelesen wird.

Verwenden Sie in Region/City einen IANA-Zonennamen (Internet Assigned Numbers Authority), beispielsweise Europe/Berlin oder America/Sao_Paulo. Diese Namen enthalten die Regeln für die Sommerzeit an diesem Ort. Der UTC-Versatz wird daher geändert, wenn sich die lokale Uhrzeit ändert. Ein Name mit festem Versatz wie Etc/GMT+5 ändert sich im Jahresverlauf nie. Außerdem ist sein Vorzeichen anders, als Sie vermutlich erwarten. Führen Sie LC_ALL=C TZ=Etc/GMT+5 date +%z aus. Der Befehl gibt -0500 aus. Vermeiden Sie solche Namen.

Warum die Einstellung nur eines Werts das Problem nur teilweise behebt

Setzen Sie GENERIC_TIMEZONE allein, wird der Schedule Trigger zur gewünschten Stunde ausgelöst, während alle Komponenten, die das Betriebssystem auslesen, weiterhin UTC verwenden. Ein Code-Knoten, der new Date().toString() aufruft, gibt eine UTC-Zeichenfolge zurück, Container-Logzeilen erhalten einen UTC-Zeitstempel, und jeder Dateiname, der anhand der Systemzeit erstellt wird, wechselt um die falsche Mitternacht.

Setzen Sie TZ allein, tritt das Gegenteil ein. docker compose exec n8n date gibt Ihre lokale Zeit aus, was wie ein Erfolg aussieht, während der Schedule Trigger weiterhin America/New_York verwendet und sechs Stunden vor oder nach der gewünschten Stunde ausgelöst wird. Diese Variante kostet am meisten Zeit, weil die Prüfung, die die meisten Benutzer zuerst durchführen, nun erfolgreich ist.

Legen Sie eine Workflow-Zeitzone fest und ändern Sie GENERIC_TIMEZONE anschließend, ignoriert dieser Workflow die Änderung. Der Wert des Workflows hat Vorrang und bleibt wirksam, bis jemand die Einstellungen dieses Workflows öffnet. Wenn ein Workflow zu einer ungewöhnlichen Uhrzeit ausgeführt wird, während seine Nachbar-Workflows korrekt laufen, liegt fast immer dieser Fall vor.

Uhren prüfen, statt zu raten

Vergleichen Sie Host und Container direkt.

date
docker compose exec n8n date
docker compose exec n8n printenv TZ GENERIC_TIMEZONE

Die ersten beiden Befehle sollten dieselbe Uhrzeit anzeigen, sobald TZ gesetzt ist. printenv gibt für jede vorhandene Variable eine Zeile aus. Zwei Ausgabezeilen bedeuten daher, dass beide Variablen gesetzt sind. Eine Zeile bedeutet, dass Sie den teilweise behobenen Zustand vor sich haben.

Fragen Sie nun n8n selbst innerhalb eines Workflows ab. Eine Container-Shell kann Ihnen nicht anzeigen, welche Zeitzone auf Workflow-Ebene gilt. Fügen Sie dem fehlerhaften Workflow einen Code-Knoten hinzu und führen Sie ihn einmal mit Execute Workflow aus.

return [
  {
    json: {
      n8n_time: $now.toISO(),
      n8n_zone: $now.zoneName,
      system_time: new Date().toString(),
    },
  },
];

n8n_zone ist die Zeitzone, die der Schedule Trigger dieses Workflows verwendet. Sie wird bereits anhand der Reihenfolge Workflow und anschließend Instanz aufgelöst und beantwortet die Frage daher direkt. system_time enthält die eigene Zeitzone des Containers aus TZ. Führen Sie den Code im fehlerhaften Workflow aus und nicht in einem neuen Workflow, weil die Einstellung auf Workflow-Ebene mit dem Workflow gespeichert wird. Wenn diese beiden Werte voneinander abweichen, haben Sie das Problem gefunden, ohne eine einzige Konfigurationsdatei zu öffnen.

Cron-Ausdrücke im Schedule-Trigger-Node

Der Schedule-Trigger bietet feste Intervalle von Sekunden bis zu Monaten sowie Custom (Cron) für alle Fälle, die damit nicht abgedeckt werden. Der Cron-Ausdruck wird in der im Workflow aufgelösten Zeitzone ausgewertet. 0 6 * * * bedeutet daher 06:00 in dieser Zeitzone und nicht 06:00 UTC. Ein fünfteiliger Ausdruck aus crontab guru kann unverändert eingefügt werden. n8n akzeptiert außerdem optional ein Sekundenfeld. In der Feldtabelle der Dokumentation steht es an erster Stelle: Sekunde, Minute, Stunde, Tag des Monats, Monat, Wochentag.

Kodieren Sie den Offset niemals manuell. 0 4 * * * auf einer UTC-Instanz einzutragen, um 06:00 in Berlin zu erreichen, ist im Winter korrekt und im gesamten Sommer um eine Stunde falsch, da Berlin im Winter UTC+1 und im Sommer UTC+2 verwendet. Legen Sie die Zeitzone fest und tragen Sie die lokale Uhrzeit ein, die Sie tatsächlich meinen.

Was die Sommerzeit mit einem Job um 02:30 macht

Eine lokale Uhrzeit ist kein garantiert definierter Zeitpunkt. Zweimal im Jahr fällt eine Stunde aus, und eine Stunde wiederholt sich. Jeder Job, der innerhalb dieser Stunden geplant ist, ist davon betroffen. Sie können das auf jedem Linux-System mit date beobachten, ohne dass n8n beteiligt ist.

LC_ALL=C TZ=Europe/Berlin date -d '2027-03-28 02:30'
date: invalid date '2027-03-28 02:30'

Das ist kein Tippfehler im Befehl. Am 2027-03-28 springt die Berliner Uhr direkt von 02:00 auf 03:00. Die lokale Uhrzeit 02:30 existiert an diesem Tag nicht, und date kann sie daher nicht in einen Zeitpunkt umwandeln. Ein Job, der auf die lokale Uhrzeit 02:30 festgelegt ist, hat keinen Zeitpunkt, zu dem er ausgeführt werden kann. Die benachbarten Uhrzeiten funktionieren: date -d '2027-03-28 01:30' wird als CET aufgelöst, date -d '2027-03-28 03:30' als CEST.

Die Umstellung im Herbst ist das Gegenstück dazu. Am 2027-10-31 wird die Berliner Uhr von 03:00 auf 02:00 zurückgestellt. Die Uhrzeit 02:30 tritt daher zweimal auf.

LC_ALL=C TZ=Europe/Berlin date -d '2027-10-31 02:30 CEST' '+%s'
LC_ALL=C TZ=Europe/Berlin date -d '2027-10-31 02:30 CET' '+%s'
1824942600
1824946200

Es handelt sich um zwei verschiedene Zeitpunkte, die beide als lokale Uhrzeit 02:30 bezeichnet werden und 3600 Sekunden auseinanderliegen. Ein dort festgelegter Job wird entweder zweimal ausgeführt oder einmal zu einer Stunde, die niemand ausgewählt hat. Beides ist für einen Abrechnungslauf oder eine Backup-Rotation nicht akzeptabel. Verlegen Sie den Zeitplan außerhalb dieses Zeitfensters. In den meisten europäischen und nordamerikanischen Zeitzonen liegt der riskante Zeitraum zwischen 00:00 und 03:00 lokaler Zeit.

Infrastruktur in UTC planen und die lokale Zeit für Menschen anzeigen

Die Standardlösung trennt die beiden Aufgaben einer Zeitzone. Maschinen benötigen ein stabiles Intervall. Menschen benötigen eine lesbare Uhrzeit.

  • Für Aufgaben, die niemand überwacht, setzen Sie die Workflow-Zeitzone auf UTC. Backups, das Vorwärmen von Caches, das Übertragen von Logs und die Berichtserstellung gehören in diese Kategorie. In UTC entspricht der Abstand zwischen zwei Ausführungen an jedem Tag des Jahres exakt dem festgelegten Abstand, weil UTC keine Sommerzeit verwendet.
  • Für Aufgaben, die eine Person liest, bleibt der Zeitplan in UTC, und Sie rechnen die Zeit erst bei der Anzeige um. Ein Ausdruck genügt: {{ $now.setZone('Europe/Berlin').toFormat('yyyy-MM-dd HH:mm') }} fügt die lokale Zeit in den Nachrichtentext ein, während der Trigger stabil bleibt.

Diese Trennung gilt auch außerhalb von n8n. Wenn ein Teil Ihrer Automatisierung als systemd-Dienst und -Timer auf dem VPS läuft, wird die Zeile OnCalendar in der Systemzeitzone ausgewertet. Diese ist eine vierte Uhr mit einer eigenen Einstellung. Wenn jeder Scheduler UTC verwendet, müssen Sie sich nur eine Regel statt vier merken. Das ist auch für alles relevant, was einen Zeitraum zusammenfasst. Denn ein n8n-AI-Agent-Workflow, der nach den Zahlen des Vortags fragt, verwendet abhängig von der Zone, in der die Auflösung erfolgt, unbemerkt jeweils andere 24 Stunden.

Fehlerbilder und die angezeigte Ausgabe

Alles wird um etwa sechs Stunden versetzt ausgeführt. GENERIC_TIMEZONE wurde nie gesetzt, daher gilt der integrierte Standardwert America/New_York. docker compose exec n8n printenv GENERIC_TIMEZONE gibt überhaupt nichts aus. Setzen Sie die Variable und erstellen Sie den Container anschließend neu.

Sie haben die Compose-Datei bearbeitet, aber nichts hat sich geändert. Sie haben docker compose restart ausgeführt. Daher verwendet der Container weiterhin seine ursprüngliche Umgebung. Führen Sie docker compose up -d aus und prüfen Sie anschließend mit docker compose exec n8n printenv TZ.

Der Trigger ist korrekt, aber die Zeitstempel sind falsch. Nur GENERIC_TIMEZONE ist gesetzt. Ein new Date() in einem Code-Knoten liest weiterhin die UTC-Zeit des Betriebssystems. Setzen Sie TZ auf denselben Wert und erstellen Sie den Container neu.

Ein Workflow ignoriert die Einstellung der Instanz. Dieser Workflow enthält in seinen Einstellungen eine eigene Zeitzone. Sie hat Vorrang vor GENERIC_TIMEZONE. Öffnen Sie den Canvas und wählen Sie Drei Punkte, Settings, Timezone.

Ein täglicher Job wurde in diesem Jahr einmal doppelt ausgeführt oder ein Tag wurde übersprungen. Die geplante Uhrzeit liegt innerhalb einer Umstellung auf Sommerzeit oder zurück auf Normalzeit. Verschieben Sie die Uhrzeit oder stellen Sie diesen Workflow auf UTC um.

FAQ

Warum wird mein n8n-Schedule-Trigger zur falschen Uhrzeit ausgelöst?

Der Workflow verwendet eine andere Zeitzone als angenommen. n8n verwendet die Workflow-Zeitzone, falls für den Workflow eine festgelegt ist. Andernfalls verwendet n8n die Instanzzeitzone aus GENERIC_TIMEZONE und danach den integrierten Standardwert America/New_York. Bei einer selbst gehosteten Instanz, für die niemand GENERIC_TIMEZONE gesetzt hat, werden Zeitpläne nach der Zeitzone von New York und nicht nach UTC ausgeführt. Deshalb entspricht die Abweichung nur selten Ihrem eigenen Abstand zu UTC. Führen Sie docker compose exec n8n printenv GENERIC_TIMEZONE aus. Keine Ausgabe bedeutet, dass die Variable nie gesetzt wurde.

Was ist der Unterschied zwischen TZ und GENERIC_TIMEZONE in n8n?

TZ ist die Zeitzone des Betriebssystems innerhalb des Containers. Sie bestimmt, was date im Container zurückgibt, welche Zeitstempel in den Container-Logzeilen erscheinen, was new Date() in einem Code-Knoten zurückgibt und welche Zeitzone jedes darin ausgeführte Script erkennt. GENERIC_TIMEZONE ist die Zeitzone der n8n-Instanz. Sie wird von Schedule-Knoten und Luxon-Ausdrücken wie $now verwendet. Wenn Sie nur eine der beiden Variablen setzen, erhalten Sie entweder einen korrekten Trigger mit falschen Zeitstempeln oder korrekte Zeitstempel mit einem Trigger, der mehrere Stunden zu früh oder zu spät ausgelöst wird. Setzen Sie beide Variablen auf denselben Wert.

Sollte ich die Workflow-Zeitzone oder GENERIC_TIMEZONE setzen?

Setzen Sie GENERIC_TIMEZONE als Standard für die gesamte Instanz. Verwenden Sie die Einstellung pro Workflow nur, wenn ein Workflow tatsächlich zu einer anderen Zeitzone gehört. Der Workflow-Wert hat Vorrang vor dem Instanzwert. Er wird bei späteren Änderungen an GENERIC_TIMEZONE nicht automatisch angepasst. Eine vergessene Überschreibung pro Workflow lässt sich daher auch Monate später nur schwer nachverfolgen.

Was geschieht mit einem für 02:30 geplanten Auftrag, wenn die Uhren umgestellt werden?

Diese lokale Uhrzeit fällt entweder aus oder tritt zweimal auf. LC_ALL=C TZ=Europe/Berlin date -d '2027-03-28 02:30' gibt date: invalid date '2027-03-28 02:30' zurück, weil die Berliner Uhr an diesem Tag von 02:00 auf 03:00 springt. Am 2027-10-31 entspricht dieselbe Anzeige der Wanduhr zwei Zeitpunkten mit einer Stunde Abstand. Planen Sie zeitgesteuerte Aufgaben nicht im lokalen Zeitraum von 00:00 bis 03:00, oder setzen Sie den Workflow auf UTC und rechnen Sie erst dort in die lokale Zeit um, wo eine Person den Wert liest.