Przejdź do treści
Toova
Wszystkie narzędzia

Składnia Wyrażeń Cron Wyjaśniona

Toova

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.