Espressioni cron spiegate: campi, passi e fusi orari

Aggiornato:

Cron è lo scheduler che esegue comandi a orari fissi sui sistemi di tipo Unix, e il suo formato a cinque campi si è diffuso ben oltre: GitHub Actions, Kubernetes e molti pannelli di hosting usano la stessa notazione. Una riga come 30 2 * * 1 si legge «alle 02:30 ogni lunedì». Quasi tutto il formato è semplice; alcune regole no, e sono quelle dietro ai job che partono all’ora sbagliata, due volte o mai. Questa guida segue lo standard POSIX e cronie, un cron molto diffuso su Linux, e segnala dove gli altri scheduler sono diversi.

I cinque campi

Una riga di crontab ha cinque campi di tempo separati da spazi, seguiti dal comando. Il job parte in ogni minuto che li soddisfa tutti, con un’eccezione per i due campi del giorno spiegata più avanti. Lo standard numera i giorni della settimana da 0 a 6, con 0 per la domenica; cronie e la maggior parte dei cron Linux accettano anche 7 per la domenica e nomi inglesi di tre lettere come mon o jan, maiuscoli o minuscoli.

CampoValoriEsempioSignifica
Minuto0–5930al minuto 30
Ora0–232dalle 02:00 alle 02:59
Giorno del mese1–311,15il 1° e il 15
Mese1–12 o jan–dec*ogni mese
Giorno della settimana0–7 o sun–sat (0 e 7 sono domenica)1-5dal lunedì al venerdì

Un asterisco indica tutti i valori del campo. Gli orari usano le 24 ore: 9 sono le 09:00 e 21 le 21:00.

Elenchi, intervalli e passi

Un campo può contenere un elenco (1,15), un intervallo (9-17) o un passo. Il passo suddivide un intervallo: 0-30/10 nel campo dei minuti indica i minuti 0, 10, 20 e 30, e */15 percorre tutti i valori dal primo, cioè i minuti 0, 15, 30 e 45. I passi si contano dall’inizio dell’intervallo e ripartono a ogni nuova ora, giorno o mese; non proseguono dal precedente.

Nel campo dei minuti danno intervalli uguali solo i passi che dividono 60 esattamente (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30). Ogni 90 minuti servono due righe: 0 0-21/3 * * * parte alle 00:00, 03:00 … 21:00, e 30 1-22/3 * * * alle 01:30, 04:30 … 22:30.

cronie accetta anche scorciatoie: @hourly, @daily (0 0 * * *), @weekly (0 0 * * 0), @monthly (0 0 1 * *), @yearly o @annually (0 0 1 1 *) e @reboot, che parte una volta all’avvio. Non fanno parte dello standard: GitHub Actions, per esempio, non le accetta.

Generatore di espressioni Cron

Giorno del mese o giorno della settimana

Quando i campi del giorno del mese e del giorno della settimana contengono qualcosa di diverso da un asterisco, lo standard dice che un giorno va bene se corrisponde uno dei due, non entrambi. Per questo 0 9 13 * 5 parte alle 09:00 ogni 13 del mese e ogni venerdì, non solo il venerdì 13. A novembre 2026 sono il 6, il 13 (un venerdì, eseguito una volta), il 20 e il 27.

Per combinarli, pianifica un campo e lascia che il comando controlli l’altro. In una crontab un % nel comando diventa un a capo, quindi va scritto \%:

Fusi orari e ora legale

Cron legge la pianificazione nel fuso orario della macchina o del servizio che la esegue, che su server e piattaforme ospitate è spesso UTC. 0 9 * * * su un server UTC parte alle 10:00 o alle 11:00 a Roma, Parigi, Berlino o Madrid, a seconda della stagione, e alle 09:00 o alle 10:00 a Lisbona e Londra. Il Brasile non ha l’ora legale, quindi a San Paolo sono sempre le 06:00. cronie permette a una crontab di fissare il proprio fuso con la variabile CRON_TZ; GitHub Actions accetta una chiave timezone accanto a cron; Kubernetes ha il campo .spec.timeZone, stabile dalla versione 1.27, e rifiuta CRON_TZ o TZ scritti nella pianificazione.

L’ora legale fa sparire o ripetere alcune ore locali. Il 29 marzo 2026 gli orologi di Roma, Parigi, Berlino e Madrid passano dalle 02:00 alle 03:00, quindi 30 2 * * * indica un’ora che non esiste; il 25 ottobre 2026 l’ora dalle 02:00 alle 03:00 si ripete due volte. A Lisbona e Londra è l’ora dalle 01:00 alle 02:00.

SchedulerJob nell’ora saltataJob nell’ora ripetuta
cronie (cambi sotto le 3 ore, job a ora fissa o meno frequenti di una volta l’ora)parte subito dopo il cambioparte una volta
GitHub Actions (con timezone)passa all’ora valida successiva: 02:30 diventa 03:00non indicato
AWS EventBridge Scheduler (con fuso orario)saltatoparte una volta
Pianificazioni in UTCnessun effettonessun effetto

cronie pianifica normalmente i job che partono più di una volta l’ora, e il suo manuale di crontab avverte in generale che le ore mancanti non corrispondono mai e quelle ripetute possono far partire il job due volte, quindi il comportamento cambia da un cron all’altro. La scelta sicura è tenere la pianificazione in UTC, oppure evitare le ore tra le 01:00 e le 03:00 locali per i job che devono partire esattamente una volta al giorno.

L’ambiente in cui gira un job

Un job di cron non riceve l’ambiente del tuo terminale. Lo standard esegue il comando con sh e un insieme minimo di variabili (HOME, LOGNAME, PATH e SHELL), quindi un comando che funziona quando lo digiti può fallire in cron perché un programma non è nel PATH o manca una variabile. Usa percorsi completi oppure imposta PATH all’inizio della crontab.

Tutto ciò che il comando stampa viene inviato per email al proprietario della crontab; cronie lo invia invece all’indirizzo in MAILTO, e non invia nulla se MAILTO è vuota. Su un server senza posta configurata quell’output si perde facilmente, quindi conviene mandarlo in un file di log.

Cron avvia ogni esecuzione all’orario previsto, che la precedente sia finita o no, quindi un job che a volte dura più del suo intervallo può finire per girare due volte insieme. flock, di util-linux, tiene un file di blocco per tutta la durata del comando; con -n rinuncia subito, con codice di uscita 1, se il blocco è occupato. Kubernetes ha la stessa scelta integrata: concurrencyPolicy è Allow per impostazione predefinita e può essere Forbid (salta la nuova esecuzione) o Replace (ferma la vecchia).

La stessa pianificazione su altre piattaforme

Il formato a cinque campi non è universale. Alcuni scheduler aggiungono i secondi o un anno, altri richiedono un punto interrogativo in uno dei due campi del giorno perché non supportano la regola dell’uno o l’altro, e altri numerano i giorni della settimana da 1. «Nei giorni feriali alle 09:00» in ciascuno:

SchedulerEspressioneNote
Cron di Linux (cronie)0 9 * * 1-5Fuso della macchina, o CRON_TZ.
GitHub Actions0 9 * * 1-5UTC se non è indicato timezone; al massimo una volta ogni 5 minuti; niente scorciatoie con @.
Kubernetes CronJob0 9 * * 1-5Fuso del controller, o .spec.timeZone.
AWS EventBridgecron(0 9 ? * MON-FRI *)Sei campi con l’anno; ? in un campo del giorno; i giorni 1–7 iniziano dalla domenica; le regole pianificate usano UTC.
Quartz (Java)0 0 9 ? * MON-FRIPrima i secondi, anno facoltativo; ? in un campo del giorno; i giorni 1–7 iniziano dalla domenica.
Timer di systemdOnCalendar=Mon..Fri *-*-* 09:00:00Giorno della settimana e data devono corrispondere entrambi; *-*~01 è l’ultimo giorno del mese.

Quando copi una pianificazione da un sistema all’altro, controlla il numero di campi e come sono numerati i giorni della settimana: 1 è lunedì in cron, ma domenica in Quartz ed EventBridge.

Perché un job non è partito

Prima di fidarti di una pianificazione, rileggila campo per campo e, su Linux, controlla le prossime esecuzioni: systemd-analyze calendar le mostra per un’espressione di timer.

Domande frequenti

La domenica è 0 o 7?

Entrambi, in cronie e nella maggior parte dei cron Linux. Lo standard POSIX definisce solo da 0 a 6, con 0 per la domenica, quindi 0 è la scelta portabile.

Cron può far partire un job ogni 30 secondi?

No: l’unità più piccola è il minuto. Gli scheduler con un campo dei secondi, come Quartz, possono farlo; su Linux anche un timer di systemd.

Come faccio partire un job ogni 90 minuti?

Con due righe: 0 0-21/3 * * * e 30 1-22/3 * * *. Insieme partono ogni ora e mezza, dalle 00:00 alle 22:30.

Cosa significa 0 0 * * 0?

Mezzanotte all’inizio di ogni domenica. In cronie equivale a @weekly.

Perché il mio job parte in giorni che non ho scelto?

Probabilmente perché sono impostati entrambi i campi del giorno. Il cron standard avvia il job quando corrisponde il giorno del mese o il giorno della settimana.

Riferimenti

  1. The Open Group Base Specifications (POSIX.1-2024) — crontab
  2. cronie — crontab(5): tables for driving cron
  3. cronie — cron(8): daylight saving time and other time changes
  4. util-linux — flock(1)
  5. GitHub Docs — Events that trigger workflows: schedule
  6. Kubernetes documentation — CronJob
  7. Amazon EventBridge — Cron expressions for scheduled rules
  8. Amazon EventBridge Scheduler — Schedule types (time zones and daylight saving)
  9. Quartz Scheduler — CronTrigger tutorial
  10. systemd — systemd.timer(5) and systemd.time(7): calendar events

Guide correlate