Składnia Wyrażeń Cron Wyjaśniona
Wyrażenia cron to jeden z tych tematów, których programiści uczą się raz, zapominają szczegóły, a potem szukają ich ponownie co sześć miesięcy. Pięcioznakowy ciąg jak 30 9 * * 1-5 może kodować zaskakująco konkretny harmonogram - "każdy dzień roboczy o 9:30 rano" - ale składnia ma wystarczająco wiele przypadków brzegowych, aby powodować prawdziwe zamieszanie: pola indeksowane od 0 vs od 1, niedziela jako i 0, i 7, różnica między standardem Unix a 6-polowym rozszerzeniem Quartz oraz subtelne zachowanie wartości kroku łączonych z zakresami.
Ten przewodnik pokrywa składnię cron od pierwszych zasad, a następnie przepracowuje każdy znak specjalny z konkretnymi przykładami. Niezależnie od tego, czy piszesz zadanie cron dla demona Linux, konfigurujesz harmonogram GitHub Actions czy konfigurujesz regułę AWS EventBridge, te same podstawowe koncepcje obowiązują - z kilkoma ważnymi różnicami platformowymi wyjaśnionymi po drodze.
Pięć Standardowych Pól
Standardowe wyrażenie cron ma pięć pól oddzielonych spacjami, czytanych od lewej do prawej: minuta, godzina, dzień miesiąca, miesiąc i dzień tygodnia. Każde pole ogranicza, kiedy zadanie się uruchamia wzdłuż tego wymiaru. Zadanie uruchamia się tylko wtedy, gdy wszystkie pięć pól pasuje równocześnie.
# Pole Pozycja Zakres Znaki specjalne
# ─────────────────────────────────────────────────
# Minuta 1 0-59 * / , -
# Godzina 2 0-23 * / , -
# Dzień miesiąca 3 1-31 * / , - ? L W
# Miesiąc 4 1-12 lub JAN-DEC * / , -
# Dzień tygodnia 5 0-7 (0=7=Nie) lub SUN-SAT * / , - ? L #
Odczytanie wyrażenia 30 9 * * 1-5: minuta 30, godzina 9, dowolny dzień miesiąca, dowolny miesiąc, dzień tygodnia 1 do 5 (poniedziałek do piątku). Wynik: 9:30 rano każdy dzień roboczy.
Pole 1: Minuta (0–59)
Pole minut określa, w której minucie (minutach) godziny zadanie powinno się uruchomić. 0 oznacza początek godziny, 30 oznacza pół po, 59 oznacza minutę przed zmianą godziny. Użycie * uruchamia zadanie co minutę.
Pole 2: Godzina (0–23)
Godziny używają czasu 24-godzinnego. 0 to północ, 12 to południe, 23 to 23:00. W cron nie ma AM/PM - zadanie o 9:00 rano to godzina 9, a zadanie o 21:00 to godzina 21.
Pole 3: Dzień Miesiąca (1–31)
W przeciwieństwie do innych pól, dzień miesiąca zaczyna się od 1, nie od 0. Poprawne wartości to 1 do 31. Jeśli określisz dzień nieistniejący w danym miesiącu (na przykład dzień 31 w kwietniu), zadanie po prostu się nie uruchamia tego miesiąca. W Quartz znak specjalny L reprezentuje ostatni dzień miesiąca, niezależnie od tego, ile dni ma.
Pole 4: Miesiąc (1–12)
Wartości miesiąca biegną od 1 (styczeń) do 12 (grudzień). Wiele schedulerów akceptuje też trzyliterowe skróty: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC. W większości implementacji są nieczułe na wielkość liter.
Pole 5: Dzień Tygodnia (0–7)
To pole z największym historycznym bagażem. Zarówno 0, jak i 7 reprezentują niedzielę - to dziwactwo zgodności z wczesnego Uniksa. Poniedziałek to 1, wtorek 2, aż do soboty 6. Trzyliterowe nazwy też tu działają: SUN, MON, TUE, WED, THU, FRI, SAT.
Gdy zarówno dzień miesiąca, jak i dzień tygodnia są określone (żaden nie jest *), większość demonów cron Unix używa logiki OR: zadanie uruchamia się, jeśli pasuje którekolwiek z pól. To zaskakuje wielu programistów. Jeśli chcesz "15. dnia, ale tylko gdy to dzień roboczy", musisz to obsłużyć w samym skrypcie zadania, nie w wyrażeniu cron.
Znaki Specjalne
Gwiazdka (*) — Każda Wartość
Gwiazdka pasuje do każdej poprawnej wartości pola. W polu minut * oznacza minuty 0 do 59. W polu miesiąca oznacza wszystkie 12 miesięcy. To najczęstszy znak w wyrażeniach cron.
Ukośnik (/) — Wartości Kroku
Ukośnik definiuje interwał kroku. */5 w polu minut oznacza "co 5 minut". Bardziej precyzyjnie oznacza "każdą wartość w zakresie podzielną przez 5 zaczynając od pierwszej wartości w zakresie". Więc */5 w minutach ewaluuje do 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55.
Kroki można łączyć z zakresami: 10-30/5 w polu minut oznacza co 5 minut między minutą 10 a minutą 30, dając 10, 15, 20, 25, 30. Krok zaczyna się od dolnej granicy zakresu.
Przecinek (,) — Lista Wartości
Przecinki tworzą listę konkretnych wartości. 1,3,5 w polu miesiąca oznacza styczeń, marzec i maj. 9,17 w polu godziny oznacza 9:00 i 17:00. Możesz wymienić tyle wartości, ile potrzeba, i łączyć je z innymi konstrukcjami.
Myślnik (-) — Zakres
Myślnik określa zakres inkluzywny. 1-5 w polu dnia tygodnia oznacza od poniedziałku do piątku. 9-17 w polu godziny oznacza od 9 rano do 17:00. Zakresy są inkluzywne na obu końcach.
Znak Zapytania (?) — Brak Konkretnej Wartości (Tylko Quartz)
Standardowy cron Unix nie obsługuje ?. W Quartz Scheduler jest używany w polach dnia miesiąca lub dnia tygodnia, aby oznaczać "nie zależy mi na tym polu". Ponieważ Quartz nie zawsze może rozwiązać konflikty między dniem miesiąca a dniem tygodnia, jedno z dwóch musi być ustawione na ?, gdy drugie jest określone. 0 0 15 * ? oznacza "15. każdego miesiąca, dowolny dzień tygodnia". 0 0 ? * MON oznacza "każdy poniedziałek, dowolny dzień miesiąca".
L — Ostatni (Tylko Quartz)
L w polu dnia miesiąca oznacza ostatni dzień miesiąca. L w polu dnia tygodnia oznacza sobotę lub, gdy połączone z liczbą (np. 5L), ostatnie wystąpienie tego dnia tygodnia w miesiącu. 5L to ostatni piątek miesiąca.
W — Najbliższy Dzień Roboczy (Tylko Quartz)
W w polu dnia miesiąca znajduje najbliższy dzień roboczy (poniedziałek-piątek) do danego dnia. 15W oznacza najbliższy dzień roboczy do 15. Jeśli 15. to sobota, zadanie uruchamia się 14. (piątek). Jeśli to niedziela, uruchamia się 16. (poniedziałek). W nie przekracza granic miesiąca.
Hash (#) — N-ty Dzień Tygodnia Miesiąca (Tylko Quartz)
# określa N-te wystąpienie dnia tygodnia w miesiącu. 5#2 oznacza drugi piątek miesiąca. 2#1 oznacza pierwszy wtorek. Jeśli określone wystąpienie nie istnieje w danym miesiącu, zadanie nie uruchamia się tego miesiąca.
Częste Wzorce Cron
# Co minutę
* * * * *
# Każdego dnia o północy (00:00)
0 0 * * *
# Każdego dnia o 9:30 rano
30 9 * * *
# Każdy poniedziałek o 8:00 rano
0 8 * * 1
# Pierwszy dzień każdego miesiąca w południe
0 12 1 * *
# Co 15 minut
*/15 * * * *
# Dni robocze o 18:00
0 18 * * 1-5 Możesz testować i walidować dowolne z nich używając narzędzia Cron Parser, które pokazuje następne pięć czasów uruchomienia dla dowolnego wyrażenia i podświetla niepoprawną składnię. Użyj Timestamp Converter, jeśli musisz zweryfikować, do czego odpowiada konkretny znacznik czasu Unix w twojej lokalnej strefie czasowej.
Rozszerzenie 6-Polowe: Quartz Scheduler
Quartz Scheduler - używany intensywnie w ekosystemie Java i przyjęty przez wiele schedulerów enterprise - dodaje obowiązkowe pole sekund na początku wyrażenia. Format staje się: sekunda minuta godzina dzień_miesiąca miesiąc dzień_tygodnia.
# Quartz 6-polowy: sekunda minuta godzina dzień miesiąc dzień_tygodnia
# Uruchom dokładnie o sekundzie 00, minucie 30, każdej godziny
0 30 * * * ?
# Uruchom o północy każdego dnia
0 0 0 * * ?
# Uruchom co 5 sekund
0/5 * * * * ?
# Ostatni dzień miesiąca o 10:00 rano
0 0 10 L * ?
# Ostatni piątek miesiąca o 15:00
0 0 15 ? * 6L
Kluczowe różnice w stosunku do standardowego cron: pole sekund (0-59) jest pierwsze i wymagane; dzień tygodnia używa 1 (niedziela) do 7 (sobota), nie 0-6; ? jest wymagane w dniu miesiąca lub dniu tygodnia, gdy drugie jest określone; oraz L, W i # to poprawne znaki specjalne.
Nigdy nie wklejaj wyrażenia Quartz do crontab Unix bez usunięcia pola sekund i dostosowania numerowania dnia tygodnia. Parsery nie są wymienne.
Cron w Różnych Systemach
Linux/Unix crontab (Vixie cron)
Oryginalna i najczęstsza forma. Pięć pól oddzielonych spacjami, po których następuje polecenie. Zmienne środowiskowe jak CRON_TZ lub TZ ustawiają strefę czasową. Crontaby użytkownika są edytowane z crontab -e; systemowe crontaby żyją w /etc/cron.d/. Skróty @reboot, @daily, @hourly, @weekly i @monthly są szeroko obsługiwane jako aliasy dla typowych wzorców.
GitHub Actions
GitHub Actions używa standardowej składni cron 5-polowej, ale strefa czasowa jest zawsze UTC - nie ma sposobu, aby określić lokalną strefę w samym wyrażeniu. Wyrażenia są ewaluowane na poziomie repozytorium, nie per zadanie. Zauważ, że zaplanowane workflowy mogą być opóźnione o kilka minut podczas okresów wysokiego obciążenia infrastruktury GitHuba.
# Składnia harmonogramu GitHub Actions (tylko 5-polowa UTC)
on:
schedule:
# Uruchom każdego dnia o 02:30 UTC
- cron: '30 2 * * *'
# Uruchom każdy poniedziałek o 09:00 UTC
- cron: '0 9 * * 1' Oficjalna dokumentacja cron GitHub Actions zauważa, że minimalny interwał to 5 minut - wyrażenia, które uruchamiałyby się częściej, są po cichu ignorowane.
AWS EventBridge (CloudWatch Events)
AWS EventBridge obsługuje zarówno wyrażenia rate (rate(5 minutes)), jak i wyrażenia cron. Ich wariant cron jest 6-polowy, ale różni się od Quartz: dzień tygodnia używa nazw Sun-Sat lub 1-7, gdzie 1 to niedziela, wszystkie czasy są w UTC, a co najmniej jedno z dnia miesiąca lub dnia tygodnia musi być ?. AWS nie obsługuje znaków W ani #.
# AWS EventBridge (cron w UTC, wariant 6-polowy)
# Uruchamia się każdego dnia o 10:00 UTC
cron(0 10 * * ? *)
# Uruchamia się o 18:00 ostatniego dnia roboczego każdego miesiąca
cron(0 18 L-1 * ? *) Kubernetes CronJob
Kubernetes CronJob używa standardowej składni cron 5-polowej. Strefa czasowa domyślnie ustawia się na strefę procesu kube-controller-manager (zwykle UTC na zarządzanych klastrach). Kubernetes 1.25 dodał pole timeZone do specyfikacji CronJob, pozwalając na konfigurację strefy per zadanie bez polegania na strefie systemowej.
Node.js (node-cron / cron npm)
Popularny pakiet node-cron obsługuje standardowe wyrażenia 5-polowe plus opcjonalne 6. pole sekund poprzedzające. Pakiet cron jest kompatybilny z Quartz. Oba obsługują ciągi stref czasowych (np. America/New_York) jako opcję konstruktora. Sprawdź dokumentację konkretnego pakietu, aby potwierdzić, którego formatu oczekuje.
Częste Pułapki
Założenia dotyczące strefy czasowej
Cron działa w strefie serwera lub kontenera, która często jest UTC w środowiskach chmurowych. Zadanie przeznaczone do uruchomienia w "9 rano czasu biznesowego" ustawione jako 0 9 * * * uruchomi się o 9 rano UTC - co może być 4 rano, 5 rano lub 11 rano w twojej lokalnej strefie w zależności od offsetu i czasu letniego. Zawsze ustawiaj CRON_TZ, używaj pola strefy schedulera lub konwertuj swój docelowy czas do UTC jawnie. Timezone Converter może pomóc ci znaleźć ekwiwalent UTC dla dowolnego czasu lokalnego w dowolnej strefie.
Logika OR dnia miesiąca / dnia tygodnia
W Unix cron, gdy zarówno pola dnia miesiąca, jak i dnia tygodnia są nie-*, demon uruchamia zadanie, jeśli którekolwiek pasuje. Więc 0 9 15 * 1 uruchamia się 15. każdego miesiąca ORAZ każdy poniedziałek - nie tylko w poniedziałki, które są 15. Aby osiągnąć logikę AND, musisz zaimplementować dodatkowe sprawdzenie wewnątrz skryptu zadania.
Mylenie wartości kroku z zakresami
*/5 oznacza "co 5 minut zaczynając od 0" (0, 5, 10 ...). 5/5 oznacza "co 5 minut zaczynając od 5" (5, 10, 15 ...). 5-30/5 oznacza "co 5 minut między minutą 5 a minutą 30" (5, 10, 15, 20, 25, 30). Mieszanie tych z zakresami może produkować nieoczekiwane wyniki, jeśli nie jesteś celowy co do wartości początkowej.
Pułapka "co sekundę"
Minimalna rozdzielczość cron w standardowym formacie 5-polowym to jedna minuta. Nie możesz zaplanować zadania cron, aby uruchamiało się co sekundę lub co kilka sekund używając crontab. Dla harmonogramowania subminutowego, użyj timera na poziomie języka (setInterval w Node.js, APScheduler w Pythonie) lub specjalnie zbudowanego systemu kolejek zamiast cron. Jeśli potrzebujesz co 30 sekund, uruchom dwa zadania cron: jedno na * * * * * i jedno, które śpi 30 sekund przed wykonaniem.
Pominięcie numerowania miesięcy
W standardowym cron miesiące biegną od 1 (styczeń) do 12 (grudzień). W niektórych API daty języków programowania miesiące są indeksowane od 0 (0 = styczeń, 11 = grudzień). Jeśli generujesz wyrażenia cron programowo z obiektów daty, dwukrotnie sprawdź, czy nie jesteś o jeden za duży w polu miesiąca.
Waliduj Swoje Wyrażenia
Cron Parser na Toova pokazuje następne pięć zaplanowanych czasów uruchomienia dla dowolnego wyrażenia, obsługuje zarówno składnię 5-polową, jak i 6-polową Quartz, oraz flaguje niepoprawne wartości inline. Do szybkiego sprawdzania zdrowotnego, crontab.guru to znane interaktywne narzędzie opisujące wyrażenia w zwykłym angielskim. Oba są użyteczne do trzymania w zakładkach.
Podczas pracy ze znacznikami czasu i zaplanowanymi czasami, Timestamp Converter tłumaczy między znacznikami Unix a datami czytelnymi dla człowieka w dowolnej strefie czasowej. Dla zadań związanych z harmonogramowaniem wrażliwym na strefę czasową, sparuj go z Timezone Converter, aby zweryfikować offsety, przejścia czasu letniego i ekwiwalenty UTC przed napisaniem finalnego wyrażenia.