Expresiones cron explicadas: campos, pasos y zonas horarias

Actualizado:

Cron es el programador que ejecuta órdenes a horas fijas en los sistemas tipo Unix, y su formato de cinco campos se ha extendido mucho más allá: GitHub Actions, Kubernetes y muchos paneles de alojamiento usan la misma notación. Una línea como 30 2 * * 1 se lee «a las 02:30 todos los lunes». Casi todo el formato es sencillo; unas pocas reglas no lo son, y son las que hay detrás de las tareas que se ejecutan a la hora equivocada, dos veces o nunca. Esta guía sigue el estándar POSIX y cronie, un cron muy usado en Linux, e indica en qué difieren otros programadores.

Los cinco campos

Una línea de crontab tiene cinco campos de tiempo separados por espacios y, después, la orden. La tarea se ejecuta en cada minuto que cumple todos ellos, con una excepción para los dos campos de día que se explica más abajo. El estándar numera los días de la semana del 0 al 6, con el 0 para el domingo; cronie y la mayoría de los cron de Linux aceptan también el 7 para el domingo, y nombres ingleses de tres letras como mon o jan, en mayúsculas o minúsculas.

CampoValoresEjemploSignifica
Minuto0–5930en el minuto 30
Hora0–232de 02:00 a 02:59
Día del mes1–311,15los días 1 y 15
Mes1–12 o jan–dec*todos los meses
Día de la semana0–7 o sun–sat (0 y 7 son domingo)1-5de lunes a viernes

Un asterisco significa todos los valores del campo. Las horas usan el reloj de 24 horas: 9 son las 09:00 y 21 las 21:00.

Listas, rangos y pasos

Un campo puede llevar una lista (1,15), un rango (9-17) o un paso. El paso divide un rango: 0-30/10 en el campo de minutos son los minutos 0, 10, 20 y 30, y */15 recorre todos los valores desde el primero, es decir, los minutos 0, 15, 30 y 45. Los pasos se cuentan desde el inicio del rango y vuelven a empezar en cada hora, día o mes nuevo; no continúan desde el anterior.

En el campo de minutos solo dan intervalos iguales los pasos que dividen 60 exactamente (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30). Cada 90 minutos hacen falta dos líneas: 0 0-21/3 * * * se ejecuta a las 00:00, 03:00 … 21:00, y 30 1-22/3 * * * a las 01:30, 04:30 … 22:30.

cronie acepta también atajos: @hourly, @daily (0 0 * * *), @weekly (0 0 * * 0), @monthly (0 0 1 * *), @yearly o @annually (0 0 1 1 *) y @reboot, que se ejecuta una vez al arrancar. No forman parte del estándar: GitHub Actions, por ejemplo, no los acepta.

Generador de expresión Cron

Día del mes o día de la semana

Cuando los campos de día del mes y de día de la semana tienen algo distinto de un asterisco, el estándar dice que un día coincide si coincide cualquiera de los dos, no ambos. Por eso 0 9 13 * 5 se ejecuta a las 09:00 todos los días 13 y todos los viernes, no solo el viernes 13. En noviembre de 2026 son los días 6, 13 (que cae en viernes y se ejecuta una vez), 20 y 27.

Para combinar los dos, programa un campo y deja que la orden compruebe el otro. En un crontab, un % en la orden se convierte en salto de línea, así que hay que escribirlo \%:

Zonas horarias y horario de verano

Cron lee la programación en la zona horaria de la máquina o del servicio que la ejecuta, que en servidores y plataformas alojadas suele ser UTC. 0 9 * * * en un servidor UTC se ejecuta a las 10:00 u 11:00 en Madrid, París, Berlín o Roma, según la época del año, y a las 09:00 o 10:00 en Lisboa y Londres. Brasil no tiene horario de verano, así que en São Paulo es siempre a las 06:00. cronie permite que un crontab fije su propia zona con la variable CRON_TZ; GitHub Actions admite una clave timezone junto a cron; Kubernetes tiene el campo .spec.timeZone, estable desde la versión 1.27, y rechaza CRON_TZ o TZ escritos dentro de la programación.

El horario de verano hace que algunas horas locales desaparezcan o se repitan. El 29 de marzo de 2026 los relojes de Madrid, París, Berlín y Roma pasan de las 02:00 a las 03:00, así que 30 2 * * * nombra una hora que no existe; el 25 de octubre de 2026 la hora de 02:00 a 03:00 ocurre dos veces. En Lisboa y Londres es la hora de 01:00 a 02:00.

ProgramadorTarea en la hora que se saltaTarea en la hora repetida
cronie (cambios de menos de 3 horas, tareas a hora fija o menos frecuentes que cada hora)se ejecuta justo después del cambiose ejecuta una vez
GitHub Actions (con timezone)pasa a la siguiente hora válida: 02:30 pasa a 03:00no se indica
AWS EventBridge Scheduler (con zona horaria)se omitese ejecuta una vez
Programaciones en UTCsin efectosin efecto

cronie programa con normalidad las tareas que se ejecutan más de una vez por hora, y su manual de crontab advierte en general que las horas que faltan nunca coinciden y las repetidas pueden ejecutarse dos veces, así que el comportamiento cambia de un cron a otro. Lo seguro es mantener la programación en UTC o evitar las horas entre las 01:00 y las 03:00 locales para tareas que deban ejecutarse exactamente una vez al día.

El entorno en que se ejecuta una tarea

Una tarea de cron no recibe el entorno de tu terminal. El estándar ejecuta la orden con sh y un conjunto mínimo de variables (HOME, LOGNAME, PATH y SHELL), así que una orden que funciona al escribirla puede fallar en cron porque un programa no está en el PATH o falta una variable. Usa rutas completas o define PATH al principio del crontab.

Todo lo que la orden imprime se envía por correo al dueño del crontab; cronie lo envía a la dirección de MAILTO y no envía nada si MAILTO está vacía. En un servidor sin correo configurado esa salida se pierde con facilidad, así que es mejor enviarla a un archivo de registro.

Cron lanza cada ejecución a su hora tanto si la anterior ha terminado como si no, así que una tarea que a veces dura más que su intervalo puede acabar ejecutándose dos veces a la vez. flock, de util-linux, mantiene un archivo de bloqueo mientras dura la orden; con -n se rinde enseguida, con código de salida 1, si el bloqueo está ocupado. Kubernetes trae la misma opción: concurrencyPolicy es Allow por defecto y puede ser Forbid (omitir la nueva ejecución) o Replace (detener la anterior).

La misma programación en otras plataformas

El formato de cinco campos no es universal. Algunos programadores añaden segundos o un año, otros exigen un signo de interrogación en uno de los dos campos de día porque no admiten la regla de uno u otro, y otros numeran los días de la semana desde 1. «Los días laborables a las 09:00» en cada uno:

ProgramadorExpresiónNotas
Cron de Linux (cronie)0 9 * * 1-5Zona horaria de la máquina, o CRON_TZ.
GitHub Actions0 9 * * 1-5UTC salvo que se indique timezone; como mucho una vez cada 5 minutos; sin atajos con @.
Kubernetes CronJob0 9 * * 1-5Zona horaria del controlador, o .spec.timeZone.
AWS EventBridgecron(0 9 ? * MON-FRI *)Seis campos con año; ? en un campo de día; los días 1–7 empiezan en domingo; las reglas programadas usan UTC.
Quartz (Java)0 0 9 ? * MON-FRISegundos primero, año opcional; ? en un campo de día; los días 1–7 empiezan en domingo.
Temporizador de systemdOnCalendar=Mon..Fri *-*-* 09:00:00El día de la semana y la fecha deben coincidir los dos; *-*~01 es el último día del mes.

Al copiar una programación entre sistemas, comprueba el número de campos y cómo se numeran los días de la semana: el 1 es lunes en cron, pero domingo en Quartz y en EventBridge.

Por qué no se ejecutó una tarea

Antes de confiar en una programación, reléela campo por campo y, en Linux, comprueba las próximas ejecuciones: systemd-analyze calendar las muestra para una expresión de temporizador.

Preguntas frecuentes

¿El domingo es 0 o 7?

Los dos, en cronie y en la mayoría de los cron de Linux. El estándar POSIX solo define del 0 al 6, con el 0 para el domingo, así que el 0 es la opción portable.

¿Puede cron ejecutar una tarea cada 30 segundos?

No: la unidad más pequeña es el minuto. Los programadores con campo de segundos, como Quartz, sí pueden; en Linux también un temporizador de systemd.

¿Cómo ejecuto una tarea cada 90 minutos?

Con dos líneas: 0 0-21/3 * * * y 30 1-22/3 * * *. Juntas se ejecutan cada hora y media, de 00:00 a 22:30.

¿Qué significa 0 0 * * 0?

Medianoche al empezar cada domingo. Equivale a @weekly en cronie.

¿Por qué mi tarea se ejecuta días que no elegí?

Probablemente porque están fijados los dos campos de día. El cron estándar ejecuta la tarea cuando coincide el día del mes o el día de la semana.

Referencias

  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

Guías relacionadas