Cara Betulkan Zon Waktu Pencetus Jadual n8n
Pencetus jadual n8n sering tersasar kerana perbezaan zon waktu. Pastikan anda menetapkan pemboleh ubah TZ, GENERIC_TIMEZONE dan zon waktu aliran kerja dengan betul sekarang.
Mengapa pencetus jadual n8n anda berjalan pada jam yang salah
Pencetus jadual n8n berjalan pada jam yang salah kerana n8n membaca zon waktu daripada tiga tempat berasingan, dan membetulkan salah satu daripadanya hanya menyelesaikan sebahagian daripada masalah. Tiga tempat tersebut ialah pemboleh ubah TZ milik kontena itu sendiri, lalai tika GENERIC_TIMEZONE, dan zon waktu yang ditetapkan di dalam aliran kerja individu. Tetapkan ketiga-tiganya sekali dan setiap jadual yang anda tulis selepas itu akan berjalan pada waktu yang anda jangkakan.
Betulkan satu andaian dahulu. n8n yang dihoskan sendiri (self-hosted) tidak menjadualkan dalam UTC (coordinated universal time). Jam kontena adalah UTC, kerana imej rasmi tidak menetapkan TZ. Penjadualan adalah lapisan yang berasingan, dan lalai yang didokumenkan oleh n8n untuk GENERIC_TIMEZONE ialah America/New_York (sehingga Ogos 2026), jadi tika yang tidak disentuh akan menjalankan Pencetus Jadualnya mengikut waktu New York. Itulah sebabnya offset yang dilaporkan oleh pengguna jarang sepadan dengan jarak mereka sendiri dari UTC. Pemilik di Berlin yang meminta jam 06:00 akan mendapat jam 12:00 waktu tempatan, dan 11:00 pada minggu-minggu bulan Mac apabila Amerika Syarikat telah beralih ke waktu penjimatan siang (daylight saving time) manakala Eropah belum.
Tiga lapisan zon waktu, dan yang mana satu diguna pakai
TZ ialah zon waktu sistem pengendalian di dalam kontena. Dokumentasi n8n menyifatkannya sebagai pemboleh ubah yang menetapkan zon waktu sistem untuk mengawal apa yang dikembalikan oleh skrip dan arahan seperti date. Ia menentukan apa yang dicetak oleh date di dalam kontena, apakah cap masa yang muncul pada baris log kontena, apa yang dikembalikan oleh new Date() dalam nod Code, dan apa yang dilihat oleh mana-mana skrip shell yang anda jalankan di dalamnya. Ia tidak memberi kesan kepada waktu pencetus Schedule Trigger berfungsi.
GENERIC_TIMEZONE ialah zon waktu instans n8n. Dokumentasi merujuknya sebagai zon waktu instans n8n dan menyatakan bahawa ia penting untuk nod jadual seperti Cron. Cron di sini bermaksud sintaks penjadualan berasaskan masa standard, dan n8n mendedahkannya sebagai pilihan Custom (Cron) pada Schedule Trigger.
Zon waktu aliran kerja ditetapkan bagi setiap aliran kerja. Buka aliran kerja pada kanvas, pilih tiga titik di penjuru kanan sebelah atas, pilih Settings, kemudian tukar nilai Timezone. Ia mengatasi GENERIC_TIMEZONE untuk aliran kerja tersebut sahaja.
Bagi Schedule Trigger, susunannya adalah tetap. n8n menggunakan zon waktu aliran kerja jika aliran kerja tersebut mempunyainya, jika tidak, ia menggunakan zon waktu instans daripada GENERIC_TIMEZONE, atau jika tiada, ia menggunakan lalai terbina dalam iaitu America/New_York. TZ tidak dirujuk pada mana-mana langkah keputusan tersebut.
Bagi tarikh di dalam nod anda, jawapannya bergantung pada jam mana yang diminta oleh kod tersebut. Luxon, pustaka tarikh di sebalik ungkapan n8n, menggunakan zon waktu n8n, jadi $now dan $today mengikut susunan aliran kerja-kemudian-instans yang sama seperti pencetus. JavaScript new Date() biasa dalam nod Code meminta sistem pengendalian, jadi ia mengikut TZ. Perbezaan tersebut adalah punca kebanyakan kekeliruan di sini: pencetus mungkin betul manakala setiap cap masa yang ditulis oleh aliran kerja tersasar beberapa jam.
Tetapkan ketiga-tiganya dalam fail Compose
Letakkan TZ dan GENERIC_TIMEZONE bersebelahan di dalam fail supaya tiada sesiapa yang menetapkan satu tetapi terlupa yang satu lagi. Fragmen di bawah merupakan bahagian yang berkaitan dengan zon waktu bagi servis yang berfungsi. Bahagian fail yang lain, iaitu reverse proxy dan sijil, diperoleh daripada n8n yang dihoskan sendiri pada VPS di sebalik 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:Gunakan docker compose up -d untuk melaksanakannya, bukan docker compose restart. Arahan restart memulakan semula container yang sama dengan persekitaran yang digunakan semasa ia dicipta, jadi perubahan pada fail tidak akan memberi kesan kepada proses yang sedang berjalan. up -d akan mengesan perubahan persekitaran dan mencipta semula container tersebut. Jika anda menyimpan nilai-nilai ini dalam fail env dan bukannya secara inline, peraturan penciptaan semula yang sama tetap terpakai, dan panduan pengendalian fail env dan rahsia Compose menerangkan dari mana fail tersebut dibaca.
Gunakan nama zon IANA (Internet Assigned Numbers Authority) dalam bentuk Region/City, seperti Europe/Berlin atau America/Sao_Paulo. Nama-nama tersebut membawa peraturan waktu musim panas (daylight saving) bagi lokasi berkenaan, jadi offset akan berubah apabila jam tempatan berubah. Nama dengan offset tetap seperti Etc/GMT+5 tidak akan berubah mengikut musim, dan tandanya adalah songsang daripada apa yang anda jangka. Jalankan LC_ALL=C TZ=Etc/GMT+5 date +%z dan ia akan memaparkan -0500. Elakkan penggunaan nama-nama tersebut.
Mengapa menetapkan salah satu sahaja menyebabkan masalah tidak selesai sepenuhnya
Menetapkan GENERIC_TIMEZONE sahaja menyebabkan Schedule Trigger mencetus pada jam yang anda mahukan, sementara segala proses yang membaca sistem pengendalian kekal pada waktu UTC. Kod nod yang memanggil new Date().toString() akan mengembalikan rentetan UTC, baris log kontena dicap dalam waktu UTC, dan sebarang nama fail yang dibina berdasarkan jam sistem akan bertukar pada tengah malam yang salah.
Menetapkan TZ sahaja akan menyebabkan perkara sebaliknya berlaku. docker compose exec n8n date memaparkan waktu tempatan anda, yang kelihatan seperti berjaya, sedangkan Schedule Trigger masih pada America/New_York dan mencetus enam jam dari waktu yang anda minta. Ini adalah versi yang paling membuang masa, kerana semakan yang dijalankan oleh kebanyakan orang pada mulanya adalah semakan yang kini lulus.
Tetapkan zon waktu aliran kerja (workflow), kemudian ubah GENERIC_TIMEZONE kemudiannya, dan aliran kerja tersebut akan mengabaikan perubahan itu. Nilai aliran kerja lebih diutamakan, dan ia terus diutamakan sehingga seseorang membuka tetapan aliran kerja tersebut. Aliran kerja yang berjalan pada waktu yang ganjil sementara aliran kerja lain berjalan dengan betul hampir selalu berpunca daripada perkara ini.
Semak jam sistem dan bukannya meneka
Bandingkan hos dan kontena secara terus.
date
docker compose exec n8n date
docker compose exec n8n printenv TZ GENERIC_TIMEZONEDua arahan pertama sepatutnya memaparkan waktu jam dinding yang sama sebaik sahaja TZ ditetapkan. printenv mencetak satu baris bagi setiap pemboleh ubah yang wujud, jadi dua baris output bermakna kedua-duanya telah ditetapkan, manakala satu baris bermakna anda sedang melihat keadaan yang hanya separuh dibaiki.
Sekarang, tanya n8n sendiri dari dalam aliran kerja (workflow), kerana shell kontena tidak dapat memberitahu anda apakah zon waktu di peringkat aliran kerja. Tambahkan nod Code ke dalam aliran kerja yang bermasalah dan jalankannya sekali dengan Execute Workflow.
return [
{
json: {
n8n_time: $now.toISO(),
n8n_zone: $now.zoneName,
system_time: new Date().toString(),
},
},
];n8n_zone ialah zon yang akan digunakan oleh Schedule Trigger aliran kerja ini, yang telah diselesaikan melalui urutan aliran kerja-kepada-instans, jadi ia menjawab soalan tersebut secara terus. system_time membawa zon kontena itu sendiri daripada TZ. Jalankannya dalam aliran kerja yang bermasalah dan bukannya dalam aliran kerja baharu, kerana tetapan peringkat aliran kerja bergerak bersama aliran kerja tersebut. Jika kedua-dua nilai itu tidak sepadan, anda telah menemui puncanya tanpa perlu membuka satu pun fail konfigurasi.
Ekspresi Cron dalam nod Schedule Trigger
Schedule Trigger menawarkan selang masa tetap daripada saat sehingga bulan, serta pilihan Custom (Cron) untuk keperluan yang tidak diliputi oleh pilihan tersebut. Ekspresi cron dibaca mengikut zon masa yang ditetapkan dalam aliran kerja (workflow), jadi 0 6 * * * bermaksud 06:00 dalam zon masa tersebut dan bukannya 06:00 UTC. Ekspresi lima medan daripada crontab guru boleh ditampal terus tanpa perubahan. n8n juga menerima medan saat pilihan, yang diletakkan pada kedudukan pertama dalam jadual medan dokumentasi: saat, minit, jam, hari bulan, bulan, hari minggu.
Jangan sesekali mengekod offset secara manual. Menulis 0 4 * * * pada instans UTC untuk mencapai 06:00 di Berlin adalah tepat pada musim sejuk tetapi akan tersilap satu jam sepanjang musim panas, kerana Berlin menggunakan UTC+1 pada musim sejuk dan UTC+2 pada musim panas. Tetapkan zon masa dan tulis jam tempatan yang anda maksudkan.
Kesan waktu jimat siang terhadap tugasan yang ditetapkan pada 02:30
Waktu jam dinding tempatan bukanlah satu detik yang terjamin. Dua kali setahun, satu jam akan hilang dan satu jam akan berulang, dan sebarang tugasan yang dijadualkan dalam tempoh jam tersebut akan terjejas. Anda boleh memerhatikan perkara ini berlaku dengan date pada mana-mana sistem Linux, tanpa melibatkan n8n.
LC_ALL=C TZ=Europe/Berlin date -d '2027-03-28 02:30'date: invalid date '2027-03-28 02:30'Itu bukan kesilapan taip dalam arahan tersebut. Pada 2027-03-28, jam di Berlin bergerak terus dari 02:00 ke 03:00, jadi waktu 02:30 tempatan tidak wujud pada hari tersebut, dan date enggan menukarkannya kepada satu detik. Tugasan yang ditetapkan pada 02:30 tempatan tidak mempunyai masa untuk dijalankan. Waktu di sekelilingnya adalah baik: date -d '2027-03-28 01:30' diselesaikan sebagai CET dan date -d '2027-03-28 03:30' diselesaikan sebagai CEST.
Peralihan musim luruh adalah imej cerminnya. Pada 2027-10-31, jam di Berlin berundur dari 03:00 ke 02:00, jadi waktu 02:30 berlaku dua kali.
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
1824946200Dua detik yang berbeza, kedua-duanya dipanggil 02:30 tempatan, dengan jarak 3600 saat antara satu sama lain. Tugasan yang ditetapkan di situ sama ada akan berjalan dua kali atau berjalan sekali pada jam yang tidak dipilih oleh sesiapa, dan kedua-dua hasil tersebut bukanlah yang diingini oleh proses pengebilan atau putaran sandaran. Alihkan jadual keluar dari tetingkap waktu tersebut. Di kebanyakan zon Eropah dan Amerika Utara, julat berisiko adalah dari 00:00 hingga 03:00 tempatan.
Jadualkan infrastruktur dalam UTC dan paparkan waktu tempatan kepada pengguna
Jawapan standard memisahkan dua tugas yang dilakukan oleh zon waktu. Mesin memerlukan selang masa yang stabil. Pengguna memerlukan jam yang boleh dibaca.
- Bagi kerja yang tidak dipantau oleh sesiapa, tetapkan zon waktu aliran kerja kepada UTC. Sandaran, pemanasan cache, penghantaran log dan penjanaan laporan tergolong dalam kategori ini. Dalam UTC, jurang antara dua pelaksanaan adalah tepat seperti yang anda tulis, pada setiap hari sepanjang tahun, kerana UTC tidak mempunyai penjimatan waktu siang (daylight saving).
- Bagi kerja yang dibaca oleh manusia, kekalkan jadual dalam UTC dan tukarkan pada titik paparan. Satu ungkapan sahaja sudah memadai:
{{ $now.setZone('Europe/Berlin').toFormat('yyyy-MM-dd HH:mm') }}meletakkan waktu tempatan dalam badan mesej manakala pencetus (trigger) kekal stabil.
Pembahagian yang sama terpakai di luar n8n. Apabila sebahagian daripada automasi anda berjalan sebagai servis dan pemasa systemd pada VPS, baris OnCalendar dibaca mengikut zon waktu sistem, iaitu jam keempat dengan tetapan tersendiri. Mengekalkan setiap penjadual pada UTC membolehkan anda hanya perlu mengingati satu peraturan dan bukannya empat. Ini juga penting bagi apa-apa yang meringkaskan sesuatu tempoh, kerana aliran kerja ejen AI n8n yang diminta untuk mendapatkan angka semalam akan menggunakan 24 jam yang berbeza secara senyap bergantung pada zon waktu yang digunakan.
Mod kegagalan dan output yang akan anda lihat
Segala-galanya berjalan dengan ralat enam jam. GENERIC_TIMEZONE tidak pernah ditetapkan, jadi nilai lalai terbina dalam America/New_York digunakan. docker compose exec n8n printenv GENERIC_TIMEZONE tidak mencetak apa-apa. Tetapkan nilai tersebut, kemudian cipta semula container.
Anda menyunting fail Compose tetapi tiada perubahan berlaku. Anda menjalankan docker compose restart, jadi container mengekalkan persekitaran asalnya. Jalankan docker compose up -d, kemudian sahkan dengan docker compose exec n8n printenv TZ.
Pemicu adalah betul tetapi cap masa adalah salah. Hanya GENERIC_TIMEZONE ditetapkan. new Date() dalam nod Code masih membaca UTC daripada sistem pengendalian. Tetapkan TZ kepada nilai yang sama dan cipta semula.
Satu aliran kerja mengabaikan tetapan instance. Aliran kerja tersebut membawa zon waktunya sendiri dalam tetapan, yang mengatasi GENERIC_TIMEZONE. Buka kanvas, klik tiga titik, Settings, Timezone.
Satu tugasan harian berjalan dua kali, atau terlepas satu hari, sekali pada tahun ini. Jam yang dijadualkan berada dalam tempoh peralihan waktu penjimatan siang (daylight saving). Ubah jam tersebut, atau pindahkan aliran kerja itu ke UTC.
FAQ
Mengapa trigger jadual n8n saya aktif pada jam yang salah?
Aliran kerja (workflow) tersebut menyelesaikan zon waktu yang berbeza daripada jangkaan anda. n8n memilih zon waktu aliran kerja jika ia ditetapkan, jika tidak, ia menggunakan zon waktu instans daripada GENERIC_TIMEZONE, atau tetapan lalai terbina dalam iaitu America/New_York. Instans yang dihoskan sendiri (self-hosted) yang tidak menetapkan GENERIC_TIMEZONE akan menjadualkan mengikut waktu New York, bukan UTC, itulah sebabnya offset tersebut jarang sepadan dengan jarak anda dari UTC. Jalankan docker compose exec n8n printenv GENERIC_TIMEZONE. Tiada output bermakna ia tidak pernah ditetapkan.
Apakah perbezaan antara TZ dan GENERIC_TIMEZONE dalam n8n?
TZ ialah zon waktu sistem pengendalian di dalam kontena. Ia mengawal apa yang dikembalikan oleh date di dalam kontena, apakah cap masa yang muncul pada baris log kontena, apa yang dikembalikan oleh new Date() dalam nod Code, dan apa yang dilihat oleh mana-mana skrip yang anda jalankan di sana. GENERIC_TIMEZONE ialah zon waktu instans n8n, dan ia adalah apa yang digunakan oleh nod jadual serta ungkapan Luxon seperti $now. Menetapkan satu tanpa yang lain akan memberikan anda trigger yang betul dengan cap masa yang salah, atau cap masa yang betul dengan trigger yang aktif pada jam yang salah. Tetapkan kedua-duanya kepada nilai yang sama.
Patutkah saya menetapkan zon waktu aliran kerja atau GENERIC_TIMEZONE?
Tetapkan GENERIC_TIMEZONE sebagai lalai untuk keseluruhan instans, dan gunakan tetapan setiap aliran kerja hanya jika satu aliran kerja benar-benar tergolong dalam zon yang berbeza. Nilai aliran kerja mengatasi nilai instans, dan ia tidak mengikut perubahan kemudian pada GENERIC_TIMEZONE, jadi penggantian (override) setiap aliran kerja yang terlupa sukar dikesan selepas beberapa bulan.
Apa yang berlaku kepada tugasan yang dijadualkan pada 02:30 apabila jam berubah?
Waktu tempatan tersebut sama ada hilang atau berlaku dua kali. LC_ALL=C TZ=Europe/Berlin date -d '2027-03-28 02:30' mengembalikan date: invalid date '2027-03-28 02:30', kerana jam Berlin melompat dari 02:00 ke 03:00 pada hari tersebut. Pada 2027-10-31, bacaan jam dinding yang sama memetakan kepada dua detik yang berbeza sejam. Elakkan kerja berjadual dalam julat waktu tempatan 00:00 hingga 03:00, atau tetapkan aliran kerja kepada UTC dan tukar kepada waktu tempatan hanya apabila ia dibaca oleh manusia.