Explicador de expresiones cron

Explica cualquier expresión cron —Vixie, Quartz, EventBridge o Jenkins—, lista las próximas ejecuciones en cualquier zona horaria y señala las trampas.

Entrada

Leída como Vixie cron.

Qué significa

A las 00:00 el día 13 del mes o en viernes

Campo a campo

CampoEscritoCoincide con
Minuto00
Hora00
Día del mes1313
Mes*cualquier valor
Día de la semana5viernes

A qué prestar atención

  • Los dos campos de día están restringidos, así que cron ejecuta esto cuando coincide cualquiera de ellos: el día del mes o el día de la semana, no ambos a la vez. Por eso 13 con viernes significa el día 13 y todos los viernes, no viernes 13.

Próximas ejecuciones

    Qué hace esta herramienta

    Te lee una expresión cron en palabras, enumera las próximas veces que se disparará de verdad en la zona horaria en la que corre la tarea, y nombra las cosas que la expresión implica pero no dice. Esa última parte es el objetivo: una expresión cron nunca está mal de una forma que produzca un error. Corre los días equivocados, en silencio, hasta que alguien se da cuenta.

    Entiende cuatro dialectos en lugar de uno. La forma de cinco campos que acepta crontab, Quartz con su campo de segundos y sus reglas de calendario, AWS EventBridge con un año al final, y Jenkins con su hash. Pegar uno en una herramienta que solo conoce otro es como la mayoría descubre que hay más de uno.

    Los campos, y cuántos son

    La expresión clásica tiene cinco campos separados por espacios, en un orden fijo: minuto, hora, día del mes, mes, día de la semana. Cada uno es un asterisco que significa «cada», un número, una lista separada por comas, un rango con guion o un paso con barra. Los meses y los días pueden escribirse con nombres de tres letras, que casi siempre son más claros que los dígitos.

    • Un asterisco significa cualquier valor que el campo pueda tomar.
    • Un rango como 9-17 significa todos los valores de 9 a 17, ambos incluidos.
    • Un paso como */15 significa cada 15.º valor desde el fondo del campo; 9-17/2 avanza dentro de un rango y 5/15 avanza desde 5 hasta el tope.
    • Una lista como 0,30 significa exactamente esos valores.
    • Un rango degenerado como 13-13 es sencillamente 13; algunas bibliotecas se equivocan aquí y lo tratan como un asterisco.

    Un sexto campo es donde los dialectos se separan. Quartz lo pone delante y lo lee como segundos; EventBridge lo pone al final y lo lee como un año. Seis campos desnudos son por tanto genuinamente ambiguos, y esta herramienta dice cómo los ha leído en lugar de elegir en silencio. Envolver la expresión en cron(...) —la sintaxis propia de EventBridge— zanja la cuestión.

    Las macros son atajos: @hourly, @daily, @midnight, @weekly, @monthly, @yearly y @annually. Se expanden a expresiones corrientes, que la herramienta muestra. @reboot es la excepción y no es una planificación en absoluto.

    Los dos campos de día, y el «o» que parece un «y»

    Una fecha se puede elegir de dos maneras distintas —por el día del mes y por el día de la semana— y cron tiene los dos campos. Cuando ambos están restringidos, la tarea se ejecuta cuando coincide cualquiera de los dos. No los dos.

    Así que 0 0 13 * 5 no es viernes 13. Es el día 13 de cada mes, y todos los viernes: unos 64 días al año en vez de uno o dos. La expresión parece una conjunción y se comporta como una disyunción, nada informa de un error, y la tarea simplemente corre más veces de lo previsto.

    La regla tiene una segunda mitad más extraña, y es la que casi nadie conoce. Cron no comprueba si un campo de día está restringido, sino si el primer carácter del campo es un asterisco. Así que un paso como */14 cuenta como asterisco aunque restrinja el campo al 1, al 15 y al 29, y su presencia devuelve los dos campos de día del «o» al «y». Dos expresiones que parecen igual de restringidas se comportan entonces de forma completamente distinta, y esta herramienta indica qué regla está en vigor.

    Quartz y EventBridge esquivan toda la cuestión negándose a que ambos campos digan algo: exactamente uno de ellos tiene que ser un signo de interrogación, que significa «ningún valor concreto, decide el otro campo».

    Pasos que no dividen su campo

    Un paso se escribe como si fuera un intervalo, y dentro de un ciclo del campo lo es. Al cruzar el límite, normalmente no.

    */7 en el campo de la hora significa las horas 0, 7, 14 y 21. Después de las 21 el campo se acaba, así que la siguiente ejecución es a las 0 del día siguiente: tres horas después, no siete. Cada ciclo termina con un hueco corto, y lo mismo pasa con */7 en minutos (un hueco de cuatro minutos tras el 56) y con cualquier otro paso que no divida su rango de forma exacta. */15 en minutos y */6 en horas son seguros; la mayoría de los números que la gente elige no lo son.

    Esto importa cuando el paso se elige para repartir trabajo. Una tarea con */7 horas no corre cada siete horas, y un límite de tasa dimensionado para siete se romperá una vez al día.

    Los días de la semana se numeran distinto según dónde

    Vixie cron numera los días de 0 a 7 con el domingo en ambos extremos, de modo que 0 y 7 son el mismo día y 1 es lunes. Quartz y EventBridge los numeran de 1 a 7 con el domingo en 1, así que allí 1 es domingo y 2 es lunes.

    Una expresión copiada de una configuración de Quartz a un crontab se ejecuta por tanto un día antes, y nada se queja en ninguna parte, porque ambas escrituras son números válidos en los dos sistemas. Los nombres de tres letras —MON, FRI— significan el mismo día en todas partes y son la defensa sencilla.

    El cambio de hora: las dos mañanas del año

    Un demonio cron no planifica instantes. Mira el reloj de pared local cada minuto y pregunta si la expresión coincide. Dos veces al año ese reloj no es una secuencia bien educada.

    Cuando salta hacia delante, una hora de lecturas no ocurre nunca. Una tarea fijada a las 02:30 no tiene 02:30 ese día. Cuando retrocede, una hora de lecturas ocurre dos veces, y una tarea fijada a la 01:30 tiene dos.

    Vixie cron distingue aquí dos clases de tarea, y la distinción vale la pena porque decide cuáles de tus tareas se ven afectadas. Una tarea fijada a una hora de reloj —hora y minuto fijos— se ejecuta exactamente una vez en ambos casos: tras un salto hacia delante se ejecuta de inmediato, y tras uno hacia atrás cron se cuida de no repetirla. Una tarea con un asterisco en la hora o en el minuto es una tarea de intervalo y sigue al reloj sin más: pierde una hora de ejecuciones en primavera y repite otra en otoño.

    Así que una copia de seguridad horaria sí corre dos veces una noche al año, y una tarea nocturna a las 02:30 sí se ejecuta en un momento inusual otra noche. Esta herramienta comprueba los próximos doce meses de la zona elegida contra tu expresión y dice cuál de los dos casos aplica, con la fecha.

    La salida fiable es planificar la tarea en UTC, o fuera del intervalo local de 01:00 a 03:00, donde no cae ninguna transición.

    En qué reloj está realmente la tarea

    Un crontab corre en la zona local de la máquina, o en la que digan CRON_TZ o TZ al principio del archivo. Rara vez es la zona de quien lee la expresión, y por eso aquí la zona horaria es un ajuste y no la de tu navegador.

    Un CronJob de Kubernetes es otra cosa: lee su planificación en UTC salvo que el manifiesto indique un campo timeZone, diga lo que diga el reloj del nodo. Una planificación escrita para el horario local de oficina y desplegada sin ese campo corre a la hora equivocada en todas partes fuera de UTC, y no cambia con las estaciones, lo que es un error o un alivio según la tarea.

    Jenkins y la H

    Jenkins añade un símbolo que ningún otro dialecto tiene: H, que parece azar y no lo es. Jenkins aplica un hash al nombre de la tarea para obtener un valor fijo dentro del rango del campo, así que la tarea corre a la misma hora cada día —su hora— mientras que cien tareas escritas H * * * * se reparten uniformemente por la hora en vez de arrancar todas en el minuto cero.

    Como el valor sale del nombre de la tarea, y el nombre no forma parte de la expresión, ninguna herramienta puede calcular las horas exactas. Esta resuelve cada H al fondo de su rango y lo dice: la forma de la planificación —cada cuánto, en qué días— es exacta, y solo el desplazamiento dentro de cada periodo es un sustituto.

    Jenkins también redefine las macros. Su @daily es @midnight, que no es medianoche sino un minuto con hash en algún punto de las tres primeras horas del día.

    Lo que cron no hace

    • No recupera lo perdido. Si la máquina estaba dormida o el demonio caído cuando tocaba una ejecución, esa ejecución no ocurre más tarde: sencillamente se pierde. anacron existe justo para esto y es otro programa.
    • No impide ejecuciones solapadas. Si una tarea tarda más que el intervalo, la siguiente arranca igualmente, y al rato hay varias. Un archivo de bloqueo es la respuesta habitual.
    • No tiene noción de segundos en la forma clásica. La resolución más fina es un minuto; cualquier cosa más rápida necesita Quartz, systemd o un bucle dentro de la propia tarea.
    • @reboot no es una planificación. Se ejecuta una vez al arrancar el demonio, así que no tiene próxima ejecución, y en una máquina que nunca se reinicia no se ejecuta jamás.
    • Una expresión rate de EventBridge cuenta desde que se creó la regla, y ese momento no está en la expresión, así que ninguna herramienta puede decir cuándo se dispara la próxima vez.

    Preguntas frecuentes

    ¿Cómo ejecuto una tarea el primer lunes de cada mes?
    No con una expresión cron corriente: eso exige un «y» entre los dos campos de día, y cron da un «o». El apaño habitual es planificar 0 0 1-7 * * y que el propio comando compruebe el día de la semana. Quartz y EventBridge pueden expresarlo directamente, como 0 0 12 ? * MON#1.
    ¿Por qué 0 0 13 * 5 se ejecuta tanto?
    Porque significa el día 13 o todos los viernes, no viernes 13. Cuando los dos campos de día están restringidos y ninguno empieza por asterisco, cron ejecuta la tarea cuando coincide cualquiera. En el dialecto clásico no hay forma de escribir un «y».
    ¿Qué diferencia hay entre */5 y 0-59/5?
    Ninguna, para el campo de los minutos: ambos dan 0, 5, 10, etc. La diferencia aparece en los dos campos de día, donde cron decide entre «y» y «o» mirando si el campo empieza por asterisco, así que */5 y 0-59/5 seleccionan los mismos días pero se combinan de distinta manera con el otro campo de día.
    ¿Mi tarea se ejecuta dos veces cuando el reloj retrocede?
    Si tiene un asterisco en la hora o en el minuto, sí: sigue al reloj, y esa hora ocurre dos veces. Si tiene hora y minuto fijos, no: Vixie cron ejecuta una tarea así una sola vez. El panel de hallazgos dice cuál es tu caso, con la fecha en que aplica.
    ¿Qué zona horaria usa una expresión cron?
    La de la máquina, salvo que CRON_TZ o TZ estén puestos en el crontab. Un CronJob de Kubernetes usa UTC salvo que el manifiesto indique timeZone. Como la zona no forma parte de la expresión, esta herramienta la pregunta en lugar de dar por supuesta la de tu navegador.
    ¿Puedo planificar algo cada 90 minutos?
    No como una sola expresión, porque cada campo cicla por su cuenta y 90 minutos no caben en una hora. La escritura habitual son dos expresiones, 0 0,3,6,9,12,15,18,21 * * * y 30 1,4,7,10,13,16,19,22 * * *, que juntas dan una ejecución cada 90 minutos.
    ¿Se envía a un servidor algo de lo que pego?
    No. El análisis, la explicación y todo el cálculo de la planificación se ejecutan en tu navegador; nada se sube ni se registra, y funciona sin conexión de red.