Expressions cron : champs, pas et fuseaux horaires
Cron est le planificateur qui lance des commandes à heures fixes sur les systèmes de type Unix, et son format à cinq champs s’est répandu bien au-delà : GitHub Actions, Kubernetes et de nombreux panneaux d’hébergement utilisent la même notation. Une ligne comme 30 2 * * 1 se lit « à 02:30 tous les lundis ». L’essentiel du format est simple ; quelques règles ne le sont pas, et ce sont elles qui expliquent les tâches lancées à la mauvaise heure, deux fois ou jamais. Ce guide suit la norme POSIX et cronie, un cron très répandu sous Linux, et signale où les autres planificateurs diffèrent.
Les cinq champs
Une ligne de crontab comporte cinq champs horaires séparés par des espaces, suivis de la commande. La tâche part à chaque minute qui les satisfait tous, avec une exception pour les deux champs de jour, expliquée plus bas. La norme numérote les jours de la semaine de 0 à 6, 0 étant le dimanche ; cronie et la plupart des cron Linux acceptent aussi 7 pour le dimanche, ainsi que des noms anglais de trois lettres comme mon ou jan, en majuscules ou minuscules.
| Champ | Valeurs | Exemple | Signifie |
|---|---|---|---|
| Minute | 0–59 | 30 | à la minute 30 |
| Heure | 0–23 | 2 | de 02:00 à 02:59 |
| Jour du mois | 1–31 | 1,15 | le 1er et le 15 |
| Mois | 1–12 ou jan–dec | * | tous les mois |
| Jour de la semaine | 0–7 ou sun–sat (0 et 7 sont le dimanche) | 1-5 | du lundi au vendredi |
Un astérisque désigne toutes les valeurs du champ. Les heures suivent l’horloge de 24 heures : 9 correspond à 09:00 et 21 à 21:00.
Listes, plages et pas
Un champ peut contenir une liste (1,15), une plage (9-17) ou un pas. Le pas découpe une plage : 0-30/10 dans le champ des minutes désigne les minutes 0, 10, 20 et 30, et */15 parcourt toutes les valeurs à partir de la première, soit les minutes 0, 15, 30 et 45. Les pas se comptent depuis le début de la plage et repartent à chaque nouvelle heure, journée ou mois ; ils ne se prolongent pas depuis le précédent.
*/15 * * * *Toutes les 15 minutes : aux minutes 0, 15, 30 et 45.0 9-17 * * 1-5À chaque heure pile de 09:00 à 17:00, du lundi au vendredi.0 0 */7 * *À minuit les 1er, 8, 15, 22 et 29 : le décompte repart chaque mois.*/25 * * * *Aux minutes 0, 25 et 50 : entre :50 et le :00 suivant, il y a 10 minutes, pas 25.
Dans le champ des minutes, seuls les pas qui divisent 60 exactement (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30) donnent des intervalles égaux. Toutes les 90 minutes, il faut deux lignes : 0 0-21/3 * * * part à 00:00, 03:00 … 21:00, et 30 1-22/3 * * * à 01:30, 04:30 … 22:30.
cronie accepte aussi des raccourcis : @hourly, @daily (0 0 * * *), @weekly (0 0 * * 0), @monthly (0 0 1 * *), @yearly ou @annually (0 0 1 1 *) et @reboot, qui s’exécute une fois au démarrage. Ils ne font pas partie de la norme : GitHub Actions, par exemple, ne les accepte pas.
Jour du mois ou jour de la semaine
Quand les champs du jour du mois et du jour de la semaine contiennent autre chose qu’un astérisque, la norme dit qu’un jour convient si l’un ou l’autre correspond, pas les deux. 0 9 13 * 5 part donc à 09:00 tous les 13 du mois et tous les vendredis, pas seulement le vendredi 13. En novembre 2026, ce sont les 6, 13 (un vendredi, lancé une seule fois), 20 et 27.
Pour combiner les deux, planifiez un champ et laissez la commande vérifier l’autre. Dans une crontab, un % dans la commande devient un saut de ligne ; il faut donc l’écrire \% :
0 9 13 * * [ "$(date +\%u)" = 5 ] && /usr/local/bin/jobSeulement le vendredi 13 : part tous les 13, et la tâche démarre quand le jour de la semaine vaut 5 (vendredi).0 18 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && /usr/local/bin/reportLe dernier jour du mois, avec GNU date (Linux) : part du 28 au 31, et la tâche démarre quand le lendemain est le 1er.
Fuseaux horaires et heure d’été
Cron lit la planification dans le fuseau horaire de la machine ou du service qui l’exécute, souvent UTC sur les serveurs et les plateformes hébergées. 0 9 * * * sur un serveur en UTC part à 10:00 ou 11:00 à Paris, Berlin, Madrid ou Rome selon la saison, et à 09:00 ou 10:00 à Lisbonne et Londres. Le Brésil n’a pas d’heure d’été : à São Paulo, c’est toujours 06:00. cronie permet à une crontab de fixer son propre fuseau avec la variable CRON_TZ ; GitHub Actions accepte une clé timezone à côté de cron ; Kubernetes dispose du champ .spec.timeZone, stable depuis la version 1.27, et refuse CRON_TZ ou TZ écrits dans la planification.
L’heure d’été fait disparaître ou se répéter certaines heures locales. Le 29 mars 2026, les horloges de Paris, Berlin, Madrid et Rome passent de 02:00 à 03:00 : 30 2 * * * désigne alors une heure qui n’existe pas ; le 25 octobre 2026, l’heure de 02:00 à 03:00 se produit deux fois. À Lisbonne et à Londres, c’est l’heure de 01:00 à 02:00.
| Planificateur | Tâche dans l’heure sautée | Tâche dans l’heure répétée |
|---|---|---|
| cronie (changements de moins de 3 heures, tâches à heure fixe ou moins fréquentes qu’une fois par heure) | exécutée juste après le changement | exécutée une fois |
| GitHub Actions (avec timezone) | reportée à l’heure valide suivante : 02:30 devient 03:00 | non précisé |
| AWS EventBridge Scheduler (avec un fuseau) | ignorée | exécutée une fois |
| Planifications en UTC | aucun effet | aucun effet |
cronie planifie normalement les tâches lancées plus d’une fois par heure, et son manuel crontab prévient de façon générale que les heures manquantes ne correspondent jamais et que les heures répétées peuvent lancer deux fois : le comportement varie donc d’un cron à l’autre. Le plus sûr est de garder la planification en UTC, ou d’éviter les heures entre 01:00 et 03:00 locales pour les tâches qui doivent tourner exactement une fois par jour.
L’environnement d’une tâche
Une tâche cron ne reçoit pas l’environnement de votre terminal. La norme exécute la commande avec sh et un jeu minimal de variables (HOME, LOGNAME, PATH et SHELL) : une commande qui fonctionne quand vous la tapez peut échouer sous cron parce qu’un programme n’est pas dans le PATH ou qu’une variable manque. Utilisez des chemins complets, ou définissez PATH en tête de la crontab.
Tout ce que la commande affiche est envoyé par courriel au propriétaire de la crontab ; cronie l’envoie plutôt à l’adresse de MAILTO, et n’envoie rien si MAILTO est vide. Sur un serveur sans messagerie configurée, cette sortie se perd facilement : envoyez-la plutôt dans un fichier journal.
0 3 * * * /usr/local/bin/backup >> /var/log/backup.log 2>&1Ajoute la sortie normale et les erreurs à un journal.5 0 * * * tar czf /srv/backup-$(date +\%F).tgz /srv/dataCrée une archive datée : les signes % sont échappés.*/5 * * * * flock -n /tmp/sync.lock /usr/local/bin/syncSaute une exécution tant que la précédente tient le verrou.
Cron lance chaque exécution à l’heure prévue, que la précédente soit terminée ou non : une tâche qui dure parfois plus longtemps que son intervalle peut donc tourner deux fois en même temps. flock, de util-linux, garde un fichier de verrou pendant la commande ; avec -n, il abandonne aussitôt, avec le code de sortie 1, si le verrou est pris. Kubernetes intègre le même choix : concurrencyPolicy vaut Allow par défaut, et peut valoir Forbid (ignorer la nouvelle exécution) ou Replace (arrêter l’ancienne).
La même planification sur d’autres plateformes
Le format à cinq champs n’est pas universel. Certains planificateurs ajoutent les secondes ou une année, d’autres exigent un point d’interrogation dans l’un des deux champs de jour parce qu’ils ne gèrent pas la règle de l’un ou l’autre, et d’autres numérotent les jours de la semaine à partir de 1. « Chaque jour ouvré à 09:00 » dans chacun :
| Planificateur | Expression | Remarques |
|---|---|---|
| Cron Linux (cronie) | 0 9 * * 1-5 | Fuseau de la machine, ou CRON_TZ. |
| GitHub Actions | 0 9 * * 1-5 | UTC sauf si timezone est indiqué ; au plus une fois toutes les 5 minutes ; pas de raccourcis en @. |
| Kubernetes CronJob | 0 9 * * 1-5 | Fuseau du contrôleur, ou .spec.timeZone. |
| AWS EventBridge | cron(0 9 ? * MON-FRI *) | Six champs avec l’année ; ? dans un champ de jour ; les jours 1–7 commencent le dimanche ; les règles planifiées sont en UTC. |
| Quartz (Java) | 0 0 9 ? * MON-FRI | Secondes en premier, année facultative ; ? dans un champ de jour ; les jours 1–7 commencent le dimanche. |
| Minuteur systemd | OnCalendar=Mon..Fri *-*-* 09:00:00 | Le jour de la semaine et la date doivent correspondre tous les deux ; *-*~01 est le dernier jour du mois. |
Quand vous copiez une planification d’un système à l’autre, vérifiez le nombre de champs et la numérotation des jours de la semaine : 1 est le lundi dans cron, mais le dimanche dans Quartz et EventBridge.
Pourquoi une tâche n’est pas partie
- La machine était éteinte ou en veille à ce moment-là : cron ne rattrape pas les exécutions manquées. Un minuteur systemd avec Persistent=true le fait, au démarrage suivant.
- La planification est dans un autre fuseau, en général UTC.
- La commande dépend du PATH, d’une variable ou du dossier courant de votre terminal.
- Un % non échappé a coupé la commande à cet endroit.
- Le jour du mois et le jour de la semaine étaient tous deux fixés, et la règle de l’un ou l’autre l’a lancée d’autres jours, ou la tâche attendait un jour qui n’est jamais venu.
- Sur une plateforme hébergée, une exécution a été retardée ou abandonnée : GitHub prévient que les exécutions planifiées peuvent être retardées aux heures chargées, comme le début de chaque heure, et désactive les planifications des dépôts publics après 60 jours sans activité.
Avant de vous fier à une planification, relisez-la champ par champ et, sous Linux, vérifiez les prochaines exécutions : systemd-analyze calendar les affiche pour une expression de minuteur.
Questions fréquentes
Le dimanche, c’est 0 ou 7 ?
Les deux, dans cronie et la plupart des cron Linux. La norme POSIX ne définit que 0 à 6, 0 étant le dimanche : 0 est donc le choix portable.
Cron peut-il lancer une tâche toutes les 30 secondes ?
Non : la plus petite unité est la minute. Les planificateurs avec un champ des secondes, comme Quartz, le peuvent ; sous Linux, un minuteur systemd aussi.
Comment lancer une tâche toutes les 90 minutes ?
Avec deux lignes : 0 0-21/3 * * * et 30 1-22/3 * * *. Ensemble, elles partent toutes les heures et demie, de 00:00 à 22:30.
Que signifie 0 0 * * 0 ?
Minuit au début de chaque dimanche. C’est l’équivalent de @weekly dans cronie.
Pourquoi ma tâche part-elle des jours que je n’ai pas choisis ?
Sans doute parce que les deux champs de jour sont fixés. Le cron standard lance la tâche quand le jour du mois ou le jour de la semaine correspond.
Références
- The Open Group Base Specifications (POSIX.1-2024) — crontab
- cronie — crontab(5): tables for driving cron
- cronie — cron(8): daylight saving time and other time changes
- util-linux — flock(1)
- GitHub Docs — Events that trigger workflows: schedule
- Kubernetes documentation — CronJob
- Amazon EventBridge — Cron expressions for scheduled rules
- Amazon EventBridge Scheduler — Schedule types (time zones and daylight saving)
- Quartz Scheduler — CronTrigger tutorial
- systemd — systemd.timer(5) and systemd.time(7): calendar events
Guides associés
- Les adresses IP expliquées : IPv4, IPv6 et les plages réservées
- Les sous-réseaux et le CIDR expliqués : préfixes, masques et hôtes utilisables
- Les enregistrements DNS expliqués : A, AAAA, CNAME, MX, TXT et NS
- Un site est-il en panne, ou est-ce chez vous ? Comment vérifier, étape par étape
- Codes de statut HTTP et erreurs Cloudflare : ce que signifient 403, 404, 429, 500, 503 et 521
- Les timestamps Unix et les fuseaux horaires expliqués
- Compter les dates : jours entre deux dates, années bissextiles et semaines ISO
- Fuseaux horaires et heure d’été : réunions entre villes
- Les formats d’image expliqués : JPEG, PNG, WebP, AVIF et HEIC
- La taille d’une image expliquée : pixels, DPI, poids et qualité
- Les photos de téléphone expliquées : HEIC, métadonnées EXIF et vie privée
- La robustesse des mots de passe expliquée : longueur, entropie et phrases de passe
- Le hachage expliqué : SHA-256, sommes de contrôle et mots de passe
- Les JSON Web Tokens expliqués : revendications, signatures, validation sûre
- Les clés API expliquées : longueur, format, stockage et rotation
- Les UUID expliqués : v4, v7 et comment choisir la bonne version
- Les QR codes expliqués : capacité, correction d’erreurs et taille d’impression
- Les pourcentages et la TVA expliqués : ajouter, retirer et cumuler
- Erreurs JSON courantes et comment les corriger
- Les fichiers CSV expliqués : séparateurs, guillemets, encodage et Excel
- Les encodages de texte expliqués : UTF-8, Base64 et encodage d’URL
- Expressions régulières : classes, quantificateurs et groupes
- Mo ou Mio, Mbit/s ou Mo/s : tailles de fichiers et débits
- Paramètres UTM : étiqueter des liens pour l’analyse d’audience
- Seuil de rentabilité, marge et ROAS : les chiffres d’une petite entreprise
- Tarifs freelance expliqués : taux horaire, TJM et heures facturables
- Modifier des PDF dans le navigateur : ce que la fusion, la division et la conversion conservent