SSD Nodes Learn Hosting plans →
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-Schedule-Trigger zur falschen Uhrzeit ausgelöst wird

Ein n8n-Schedule-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. Diese drei Quellen sind die TZ-Variable des Containers, der Instanzstandard GENERIC_TIMEZONE und eine Zeitzone, die innerhalb eines einzelnen Workflows festgelegt wird. Setzen Sie alle drei einmal. Danach wird jeder neu erstellte Zeitplan wie erwartet ausgeführt.

Korrigieren Sie zuerst eine verbreitete Annahme. Eine neue selbst gehostete n8n-Instanz plant nicht in UTC (koordinierte Weltzeit). Die Uhr des Containers läuft in UTC, weil das offizielle Image keine TZ setzt. Die Zeitplanung ist davon unabhängig. Der dokumentierte Standardwert von n8n für GENERIC_TIMEZONE ist America/New_York (Stand: Oktober 2026). Eine unveränderte Instanz führt ihre Schedule Trigger daher nach der Zeit von New York aus. Deshalb entspricht der gemeldete Versatz nur selten dem tatsächlichen Abstand zur UTC. Ein Betreiber in Berlin, der 06:00 festlegt, erhält 12:00 Ortszeit. In den Wochen im März und in der Woche um den Monatswechsel von Oktober und November erhält er 11:00, wenn in den Vereinigten Staaten die Sommerzeit gilt, in Europa jedoch 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 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. Ändern Sie dann den Wert Timezone. Dieser überschreibt GENERIC_TIMEZONE für diesen Workflow. Alle Einstellungen auf dieser Seite gehören zur kostenlosen Self-Hosted-Version. Daher hängt die korrekte Ausführung von Zeitplänen nicht von einem kostenpflichtigen Tarif ab. Die Funktionen, die einen Lizenzschlüssel benötigen, bilden eine vollständig separate Liste.

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 diese Intervalle nicht abdecken. Der Cron-Ausdruck wird in der für den Workflow ermittelten Zeitzone ausgewertet. 0 6 * * * bedeutet daher 06:00 in dieser Zeitzone und nicht 06:00 UTC. Ein Ausdruck mit fünf Feldern aus crontab guru kann unverändert eingefügt werden. n8n akzeptiert außerdem ein optionales Sekundenfeld. In der Feldtabelle der Dokumentation steht es an erster Stelle: Sekunde, Minute, Stunde, Tag des Monats, Monat, Wochentag.

Kodieren Sie den Versatz niemals manuell. 0 4 * * * auf einer UTC-Instanz einzutragen, um 06:00 in Berlin zu erreichen, ist im Sommer korrekt und im gesamten Winter eine Stunde zu früh. Berlin verwendet im Sommer UTC+2 und im Winter UTC+1. Vom letzten Sonntag im März bis zum letzten Sonntag im Oktober wird dieser Ausdruck um 06:00 Berliner Zeit ausgeführt. Im restlichen Jahr wird er um 05:00 ausgeführt. Nur 0 5 * * * würde dann 06:00 erreichen. Legen Sie die Zeitzone fest und verwenden Sie die lokale Uhrzeit, 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.