Vai al contenuto
Toova
Tutti gli strumenti

Sintassi delle Espressioni Cron Spiegata

Toova

Le espressioni cron sono uno di quegli argomenti che gli sviluppatori imparano una volta, dimenticano i dettagli e poi cercano di nuovo ogni sei mesi. Una stringa di cinque caratteri come 30 9 * * 1-5 può codificare una pianificazione sorprendentemente specifica — "ogni giorno feriale alle 9:30" — ma la sintassi ha abbastanza casi limite da generare vera confusione: campi con indice 0 contro indice 1, domenica che è sia 0 che 7, la differenza tra lo standard Unix e l'estensione a sei campi di Quartz, e il comportamento sottile dei valori di passo combinati con gli intervalli.

Questa guida copre la sintassi cron dai primi principi, poi analizza ogni carattere speciale con esempi concreti. Che tu stia scrivendo un cron job per un demone Linux, configurando una pianificazione su GitHub Actions o impostando una regola AWS EventBridge, gli stessi concetti di base si applicano — con alcune importanti differenze tra le piattaforme spiegate lungo il percorso.

I Cinque Campi Standard

Un'espressione cron standard ha cinque campi separati da spazi, letti da sinistra a destra: minuto, ora, giorno del mese, mese e giorno della settimana. Ogni campo vincola quando il job viene eseguito lungo quella dimensione. Un job viene eseguito solo quando tutti e cinque i campi corrispondono simultaneamente.

# Campo          Posizione  Intervallo       Caratteri speciali
# ─────────────────────────────────────────────────────────────
# Minuto              1      0-59             * / , -
# Ora                 2      0-23             * / , -
# Giorno del mese     3      1-31             * / , - ? L W
# Mese                4      1-12 o JAN-DEC   * / , -
# Giorno settimana    5      0-7 (0=7=Dom) o SUN-SAT  * / , - ? L #

Leggendo un'espressione come 30 9 * * 1-5: minuto 30, ora 9, qualsiasi giorno del mese, qualsiasi mese, giorno della settimana da 1 a 5 (lunedì al venerdì). Risultato: ogni giorno feriale alle 9:30.

Campo 1: Minuto (0–59)

Il campo dei minuti specifica in quale minuto/i dell'ora il job deve essere eseguito. 0 significa l'inizio dell'ora, 30 significa la mezz'ora, 59 significa un minuto prima che l'ora cambi. Usando * il job viene eseguito ogni minuto.

Campo 2: Ora (0–23)

Le ore usano il formato 24 ore. 0 è mezzanotte, 12 è mezzogiorno, 23 è le 23:00. Non esiste AM/PM nel cron — un job alle 9:00 è l'ora 9, e un job alle 21:00 è l'ora 21.

Campo 3: Giorno del Mese (1–31)

A differenza degli altri campi, il giorno del mese inizia da 1, non da 0. I valori validi sono da 1 a 31. Se specifichi un giorno che non esiste in un determinato mese (ad esempio, il giorno 31 ad aprile), il job semplicemente non viene eseguito quel mese. In Quartz, il carattere speciale L rappresenta l'ultimo giorno del mese, indipendentemente da quanti giorni ha.

Campo 4: Mese (1–12)

I valori del mese vanno da 1 (gennaio) a 12 (dicembre). Molti scheduler accettano anche abbreviazioni di tre lettere: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC. Queste sono insensibili alle maiuscole nella maggior parte delle implementazioni.

Campo 5: Giorno della Settimana (0–7)

Questo è il campo con più bagaglio storico. Sia 0 che 7 rappresentano la domenica — questa è un'anomalia di compatibilità del primo Unix. Lunedì è 1, martedì 2, fino a sabato 6. Anche i nomi a tre lettere funzionano qui: SUN, MON, TUE, WED, THU, FRI, SAT.

Quando sia il giorno del mese che il giorno della settimana sono specificati (nessuno dei due è *), la maggior parte dei demoni cron Unix usa la logica OR: il job viene eseguito se corrisponde a uno dei due campi. Questo sorprende molti sviluppatori. Se vuoi "il 15, ma solo se è un giorno feriale," devi gestirlo nello script del job stesso, non nell'espressione cron.

Caratteri Speciali

Asterisco (*) — Ogni Valore

L'asterisco corrisponde a ogni valore valido per un campo. Nel campo dei minuti, * significa i minuti da 0 a 59. Nel campo del mese, significa tutti e 12 i mesi. È il carattere più comune nelle espressioni cron.

Barra (/) — Valori di Passo

La barra definisce un intervallo di passo. */5 nel campo dei minuti significa "ogni 5 minuti." Più precisamente, significa "ogni valore nell'intervallo che è divisibile per 5 a partire dal primo valore dell'intervallo." Quindi */5 nei minuti si traduce in 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55.

I passi possono essere combinati con gli intervalli: 10-30/5 nel campo dei minuti significa ogni 5 minuti tra il minuto 10 e il minuto 30, producendo 10, 15, 20, 25, 30. Il passo parte dal limite inferiore dell'intervallo.

Virgola (,) — Lista di Valori

Le virgole creano una lista di valori specifici. 1,3,5 nel campo del mese significa gennaio, marzo e maggio. 9,17 nel campo delle ore significa le 9:00 e le 17:00. Puoi elencare tutti i valori che vuoi e combinarli con altri costrutti.

Trattino (-) — Intervallo

Un trattino specifica un intervallo inclusivo. 1-5 nel campo del giorno della settimana significa da lunedì a venerdì. 9-17 nel campo delle ore significa dalle 9:00 alle 17:00. Gli intervalli sono inclusivi su entrambi i lati.

Punto Interrogativo (?) — Nessun Valore Specifico (Solo Quartz)

Il cron Unix standard non supporta ?. In Quartz Scheduler, viene usato nei campi del giorno del mese o del giorno della settimana per indicare "non mi importa di questo campo." Poiché Quartz non riesce sempre a risolvere i conflitti tra giorno del mese e giorno della settimana, uno dei due deve essere impostato su ? quando l'altro è specificato. 0 0 15 * ? significa "il 15 di ogni mese, qualsiasi giorno della settimana." 0 0 ? * MON significa "ogni lunedì, qualsiasi giorno del mese."

L — Ultimo (Solo Quartz)

L nel campo del giorno del mese significa l'ultimo giorno del mese. L nel campo del giorno della settimana significa sabato, oppure quando combinato con un numero (es. 5L), l'ultima occorrenza di quel giorno della settimana nel mese. 5L è l'ultimo venerdì del mese.

W — Giorno Feriale Più Vicino (Solo Quartz)

W nel campo del giorno del mese trova il giorno feriale più vicino (lunedì–venerdì) al giorno indicato. 15W significa il giorno feriale più vicino al 15. Se il 15 è sabato, il job viene eseguito il 14 (venerdì). Se è domenica, viene eseguito il 16 (lunedì). W non attraversa i confini del mese.

Hash (#) — Ennesimo Giorno della Settimana del Mese (Solo Quartz)

# specifica la N-esima occorrenza di un giorno della settimana in un mese. 5#2 significa il secondo venerdì del mese. 2#1 significa il primo martedì. Se l'occorrenza specificata non esiste in un determinato mese, il job non viene eseguito quel mese.

Pattern Cron Comuni

# Ogni minuto
* * * * *

# Ogni giorno a mezzanotte (00:00)
0 0 * * *

# Ogni giorno alle 9:30
30 9 * * *

# Ogni lunedì alle 8:00
0 8 * * 1

# Primo giorno di ogni mese a mezzogiorno
0 12 1 * *

# Ogni 15 minuti
*/15 * * * *

# Giorni feriali alle 18:00
0 18 * * 1-5

Puoi testare e validare ognuno di questi usando lo strumento Cron Parser, che mostra i prossimi cinque orari di esecuzione per qualsiasi espressione e segnala la sintassi non valida inline. Usa il Convertitore di Timestamp se hai bisogno di verificare a cosa corrisponde uno specifico timestamp Unix nel tuo fuso orario locale.

L'Estensione a 6 Campi: Quartz Scheduler

Quartz Scheduler — molto utilizzato nell'ecosistema Java e adottato da molti scheduler enterprise — aggiunge un campo obbligatorio per i secondi all'inizio dell'espressione. Il formato diventa: secondo minuto ora giorno-del-mese mese giorno-della-settimana.

# Quartz 6 campi: secondo minuto ora giorno mese giorno-settimana
# Esegui esattamente a 00 secondi, 30 minuti, ogni ora
0 30 * * * ?

# Esegui a mezzanotte ogni giorno
0 0 0 * * ?

# Esegui ogni 5 secondi
0/5 * * * * ?

# Ultimo giorno del mese alle 10:00
0 0 10 L * ?

# Ultimo venerdì del mese alle 15:00
0 0 15 ? * 6L

Differenze chiave rispetto al cron standard: il campo dei secondi (0–59) è il primo ed è obbligatorio; il giorno della settimana usa 1 (domenica) fino a 7 (sabato), non 0–6; ? è obbligatorio nel giorno del mese o nel giorno della settimana quando l'altro è specificato; e L, W e # sono caratteri speciali validi.

Non incollare mai un'espressione Quartz in un crontab Unix senza rimuovere il campo dei secondi e adeguare la numerazione del giorno della settimana. I parser non sono intercambiabili.

Cron in Diversi Sistemi

Linux/Unix crontab (Vixie cron)

La forma originale e più comune. Cinque campi separati da spazi, seguiti dal comando. Le variabili d'ambiente come CRON_TZ o TZ impostano il fuso orario. I crontab degli utenti si modificano con crontab -e; i crontab di sistema si trovano in /etc/cron.d/. Le scorciatoie @reboot, @daily, @hourly, @weekly e @monthly sono ampiamente supportate come alias per i pattern più comuni.

GitHub Actions

GitHub Actions usa la sintassi cron standard a 5 campi, ma il fuso orario è sempre UTC — non c'è modo di specificare un fuso orario locale nell'espressione stessa. Le espressioni vengono valutate a livello di repository, non per job. Nota che i workflow pianificati possono subire ritardi di diversi minuti durante i periodi di carico elevato sull'infrastruttura di GitHub.

# Sintassi schedule di GitHub Actions (5 campi, solo UTC)
on:
  schedule:
    # Esegui ogni giorno alle 02:30 UTC
    - cron: '30 2 * * *'
    # Esegui ogni lunedì alle 09:00 UTC
    - cron: '0 9 * * 1'

La documentazione ufficiale di GitHub Actions per cron nota che l'intervallo minimo è di 5 minuti — le espressioni che verrebbero eseguite più frequentemente vengono silenziosamente ignorate.

AWS EventBridge (CloudWatch Events)

AWS EventBridge supporta sia le espressioni di frequenza (rate(5 minutes)) che le espressioni cron. La loro variante cron è a 6 campi ma differisce da Quartz: il giorno della settimana usa i nomi Sun–Sat o 1–7 dove 1 è domenica, tutti gli orari sono UTC e almeno uno tra giorno del mese o giorno della settimana deve essere ?. AWS non supporta i caratteri W o #.

# AWS EventBridge (cron in UTC, variante a 6 campi)
# Esegui ogni giorno alle 10:00 AM UTC
cron(0 10 * * ? *)

# Esegui alle 18:00 nell'ultimo giorno feriale di ogni mese
cron(0 18 L-1 * ? *)

Kubernetes CronJob

Kubernetes CronJob usa la sintassi cron standard a 5 campi. Il fuso orario predefinito è quello del processo kube-controller-manager (di solito UTC sui cluster gestiti). Kubernetes 1.25 ha aggiunto il campo timeZone alla spec del CronJob, consentendo la configurazione del fuso orario per ogni job senza dover dipendere dal fuso orario del sistema.

Node.js (node-cron / cron npm)

Il popolare pacchetto node-cron supporta le espressioni standard a 5 campi più un opzionale 6° campo per i secondi anteposto. Il pacchetto cron è compatibile con Quartz. Entrambi supportano stringhe di fuso orario (es. America/New_York) come opzione del costruttore. Controlla la documentazione del tuo pacchetto specifico per confermare quale formato si aspetta.

Insidie Comuni

Assunzioni sul fuso orario

Cron viene eseguito nel fuso orario del server o del container, che negli ambienti cloud è spesso UTC. Un job pensato per essere eseguito "alle 9 del mattino ora lavorativa" impostato come 0 9 * * * verrà eseguito alle 9:00 UTC — che potrebbe essere le 4:00, le 5:00 o le 11:00 nel tuo fuso orario locale a seconda dell'offset e dell'ora legale. Imposta sempre CRON_TZ, usa il campo del fuso orario del tuo scheduler, oppure converti esplicitamente l'orario target in UTC. Il Convertitore di Fuso Orario può aiutarti a trovare l'equivalente UTC per qualsiasi ora locale in qualsiasi fuso orario.

Logica OR tra giorno del mese e giorno della settimana

Nel cron Unix, quando sia il campo del giorno del mese che quello del giorno della settimana sono diversi da *, il demone esegue il job se corrisponde a uno dei due campi. Quindi 0 9 15 * 1 viene eseguito il 15 di ogni mese E ogni lunedì — non solo nei lunedì che capitano il 15. Per ottenere la logica AND, devi implementare il controllo aggiuntivo nello script del job.

Confondere i valori di passo con gli intervalli

*/5 significa "ogni 5 minuti a partire da 0" (0, 5, 10 ...). 5/5 significa "ogni 5 minuti a partire da 5" (5, 10, 15 ...). 5-30/5 significa "ogni 5 minuti tra il minuto 5 e il minuto 30" (5, 10, 15, 20, 25, 30). Mescolarli con gli intervalli può produrre risultati inaspettati se non sei preciso sul valore di partenza.

La trappola "ogni secondo"

La risoluzione minima di cron nel formato standard a 5 campi è un minuto. Non puoi pianificare un cron job per essere eseguito ogni secondo o ogni pochi secondi usando un crontab. Per la pianificazione sub-minuto, usa un timer a livello di linguaggio (setInterval in Node.js, APScheduler in Python) o un sistema di code dedicato anziché cron. Se hai bisogno di ogni 30 secondi, esegui due cron job: uno a * * * * * e uno che dorme 30 secondi prima dell'esecuzione.

Errore nella numerazione dei mesi

Nel cron standard, i mesi vanno da 1 (gennaio) a 12 (dicembre). In alcune API di date dei linguaggi di programmazione, i mesi sono indicizzati da 0 (0 = gennaio, 11 = dicembre). Se stai generando espressioni cron in modo programmico da oggetti data, verifica di non essere sfasato di uno nel campo del mese.

Valida le Tue Espressioni

Il Cron Parser su Toova mostra i prossimi cinque orari di esecuzione pianificati per qualsiasi espressione, supporta sia la sintassi Quartz a 5 che a 6 campi e segnala i valori non validi inline. Per un rapido controllo di sanità, crontab.guru è uno strumento interattivo ben noto che descrive le espressioni in inglese semplice. Entrambi sono utili da tenere nei segnalibri.

Quando lavori con timestamp e orari pianificati, il Convertitore di Timestamp traduce tra timestamp Unix e date leggibili in qualsiasi fuso orario. Per i job che coinvolgono una pianificazione sensibile al fuso orario, abbinalo al Convertitore di Fuso Orario per verificare gli offset, le transizioni dell'ora legale e gli equivalenti UTC prima di scrivere la tua espressione finale.