Expresión cron: leer la sintaxis y calcular las próximas ejecuciones

Expresión cron: leer la sintaxis y calcular las próximas ejecuciones

Lee una expresión cron campo a campo, comprueba sus próximas ejecuciones en UTC o en hora local y evita las trampas de pasos, zonas horarias y dialectos.

16.10.2026
19 min de lectura
Compartir este artículo:
CronProgramación de tareasZona horariaDevOpsTutorial

Una expresión cron se lee campo a campo y se comprueba con fechas

Una línea como */15 9-17 * * 1-5 gobierna una copia de seguridad, un workflow de CI o un CronJob de Kubernetes. Es corta y casi nadie la relee. Si lees mal un campo, la tarea se lanza a una hora equivocada, dos veces o nunca. El analizador cron acepta cinco campos (minuto, hora, día del mes, mes, día de la semana) o seis, con los segundos al principio. También acepta alias como @daily y @hourly. Muestra una frase que resume la programación y el valor de cada campo. Además, da las próximas 5, 10 o 25 ejecuciones, en UTC o en la zona horaria de tu navegador. El cálculo se hace en tu pestaña y la expresión no se envía a nadie. Esta guía repasa la sintaxis y los alias, y después enseña a leer el resultado. Después vienen las trampas que salen caras. Un paso no cuadra, dos campos de día se combinan en un OR, una fecha no existe, y la zona horaria y el cambio de hora del 25 de octubre de 2026 lo desplazan todo. Al final compara los dialectos de crontab, Kubernetes, GitHub Actions y AWS EventBridge, y rehace los cálculos en código. Las herramientas relacionadas están en el hub de utilidades para desarrolladores.

Cinco campos estándar, o seis con los segundos al principio. Minuto de 0 a 59, hora de 0 a 23, día del mes de 1 a 31, mes de 1 a 12 o de JAN a DEC, día de la semana de 0 a 7 o de SUN a SAT (0 y 7 son domingo)
Listas (<code>1,15</code>), rangos (<code>9-17</code>) y pasos (<code>*/15</code>, <code>10-50/10</code>). Los nombres de meses y días valen en mayúsculas o en minúsculas
Los alias <code>@hourly</code>, <code>@daily</code>, <code>@midnight</code>, <code>@weekly</code>, <code>@monthly</code>, <code>@yearly</code> y <code>@annually</code>, sustituidos por su forma de cinco campos en el cuadro de entrada. <code>@reboot</code> se rechaza
Una frase de resumen para las programaciones habituales (cada 15 minutos, todos los días a las 09:00, de lunes a viernes) y, si no, el detalle campo a campo
Las próximas 5, 10 o 25 ejecuciones, con el tiempo que falta para la primera, en UTC o en la hora local del navegador
Un aviso cuando el día del mes y el día de la semana están ambos fijados: cualquiera de los dos dispara la ejecución
Sin subida de datos: el cálculo se queda en el navegador

Para qué sirve el analizador y dónde termina

Buenos usos

El analizador responde a una sola pregunta: ¿en qué momentos se dispara esta expresión? Úsalo para comprobarlo antes de desplegar.

Releer la línea de un compañero o un crontab antiguo antes de copiarlos: primero la frase de resumen, después los cinco campos
Comprobar un paso. <code>*/7</code> no repite la tarea cada 7 minutos (ver más abajo) y las próximas ejecuciones lo demuestran
Comprobar un fin de mes como <code>0 0 31 * *</code>, que se salta los meses de 30 días. Pide 25 ejecuciones para ver el patrón
Leer la programación en tu zona horaria pasando la visualización a Local, sabiendo que el cálculo sigue en UTC (ver los errores más abajo)
Escribir un alias en su forma de cinco campos antes de pegarlo en una herramienta que no admite macros, como GitHub Actions
Copiar la descripción o la lista de ejecuciones en un ticket o en una revisión de código, para que quien revisa vea las fechas además de la línea
Lo que corresponde a otras herramientas

El analizador calcula fechas. El resto de la cadena se comprueba en otra parte.

Convertir el epoch de un registro o de un token en una fecha legible: el <a href="/es/unix-timestamp" class="text-primary hover:underline">conversor de timestamp Unix</a>
Comprobar que un manifiesto de Kubernetes está bien formado: el <a href="/es/validate-kubernetes" class="text-primary hover:underline">validador de Kubernetes</a>, presentado en la <a href="/es/blog/kubernetes-validar-manifiestos-yaml-en-linea" class="text-primary hover:underline">guía de Kubernetes</a>
Comprobar que un workflow de GitHub Actions está bien formado: el <a href="/es/validate-github-actions" class="text-primary hover:underline">validador de GitHub Actions</a>, presentado en la <a href="/es/blog/github-actions-lint-workflow-yaml" class="text-primary hover:underline">guía de GitHub Actions</a>. La <a href="/es/blog/gitlab-ci-formatear-validar-yaml" class="text-primary hover:underline">guía de GitLab CI</a> hace lo mismo con <code>.gitlab-ci.yml</code>
Probar la tarea en sí: el analizador no lanza nada, no lee ningún registro y no sabe si la máquina estaba encendida
Vigilar la ejecución real: una programación correcta no prueba que la tarea se ejecutó. Hacen falta registros, una alerta o un control del último éxito
Manejar las particularidades de un dialecto: el analizador no conoce <code>?</code>, ni <code>L</code>, <code>W</code> y <code>#</code>, ni el campo del año
Programar una ejecución única: cron repite, no sabe decir «una sola vez». Para eso existe <code>at</code>

Leer los resultados sin equivocarse

El resultado, campo a campo

Introduce la expresión en el analizador cron. Las fechas de abajo parten del viernes 16 de octubre de 2026 a las 12:00 UTC. La herramienta parte del momento actual, así que tus fechas serán otras.

<code>0 9 * * 1-5</code> da la frase «A las 09:00 en días laborables (lun–vie)». Las próximas ejecuciones son el lunes 19, martes 20, miércoles 21, jueves 22 y viernes 23 de octubre a las 09:00 UTC
<code>*/15 9-17 * * 1-5</code> no tiene una frase exacta. La herramienta escribe «Desglose de la programación», añade una nota y da los cinco campos y las ejecuciones: el viernes 16 a las 12:15, 12:30, 12:45, 13:00 y 13:15
La última salida del día para <code>9-17</code> con <code>*/15</code> es a las 17:45. El rango de horas incluye la hora 17 entera, hasta las 17:59
Las cinco casillas repiten cada campo tal como lo escribiste. Solo se desarrollan los alias: <code>@daily</code> pasa a ser <code>0 0 * * *</code> en el cuadro de entrada
El día de la semana admite 0 y 7 para el domingo. <code>0 0 * * 7</code> y <code>0 0 * * 0</code> dan las mismas fechas
La línea «Próxima» indica cuánto falta para la primera ejecución, lo que basta para detectar una expresión que solo se dispara dentro de seis meses
Un paso no se cuenta desde la última ejecución

Un paso se calcula dentro del rango del campo. Al comienzo de cada rango, la cuenta vuelve a cero.

<code>*/7 * * * *</code> se dispara en los minutos 0, 7, 14 y así hasta el 56, y luego vuelve al minuto 0: 12:49, 12:56 y después 13:00, es decir, 4 minutos más tarde. La página de manual de crontab da el mismo caso con <code>*/35</code>
<code>0 */5 * * *</code> se dispara a las 0, 5, 10, 15 y 20 horas. Después de las 20:00 llegan las 00:00, de modo que el intervalo es de 4 horas y no de 5
<code>0 0 */2 * *</code> afecta a los días 1, 3, 5 hasta el 31. Al 31 de octubre le sigue el 1 de noviembre, dos días seguidos
Para un verdadero «cada N unidades», elige un N que divida 60 (minutos) o 24 (horas), o cuenta en el script a partir de la hora del último éxito
Un paso sobre un valor suelto, como <code>20/15</code>, parte de ese valor y llega hasta el máximo del campo: minutos 20, 35 y 50
Cuando se combinan día del mes y día de la semana

Cuando los dos campos están rellenos, cron no los combina con AND. Lanza la tarea si coincide cualquiera de los dos (según la página de manual de crontab). La herramienta lo señala con una nota bajo la frase de resumen.

<code>0 0 1 * 1</code> se dispara el día 1 del mes y todos los lunes. Las próximas ejecuciones son los lunes 19 y 26 de octubre, el domingo 1 de noviembre y después los lunes 2 y 9 de noviembre
El primer lunes del mes no existe en cron estándar. Escribir <code>1-7</code> para el día del mes y <code>1</code> para el lunes da un OR y, por tanto, demasiadas ejecuciones
Solución: programar todos los lunes y comprobar la fecha en el comando, con <code>[ "$(date +\%d)" -le 7 ]</code>. En un crontab, el signo % se escribe <code>\%</code>
Cuando uno de los dos campos vale <code>*</code>, el otro decide solo: <code>0 9 * * 1-5</code> no tiene OR
Fechas que no están en el calendario

Una expresión válida puede no dispararse nunca. La herramienta busca unos dos años hacia delante y te lo dice.

<code>0 0 30 2 *</code> se refiere a un 30 de febrero: ninguna ejecución. La herramienta muestra «No hay ejecuciones próximas en la ventana de búsqueda»
<code>0 0 31 * *</code> solo se dispara en los meses de 31 días. Desde el 16 de octubre de 2026 son el 31 de octubre y el 31 de diciembre de 2026, y después el 31 de enero, el 31 de marzo, el 31 de mayo, el 31 de julio y el 31 de agosto de 2027
<code>0 0 29 2 *</code> tiene una sola fecha en la ventana, el 29 de febrero de 2028. La herramienta muestra «Solo resultados parciales antes del límite de búsqueda», y es normal: la siguiente cae en 2032
El último día del mes no tiene escritura en cron estándar. Programa del 28 al 31 y comprueba en el comando la fecha de mañana, por ejemplo con <code>[ "$(date -d tomorrow +\%d)" = 01 ]</code> (con GNU <code>date</code>)

Cuatro errores que solo se ven en producción

Creer que la visualización Local cambia la zona horaria de la programación

El analizador calcula siempre en UTC. La opción Local solo cambia cómo se escriben las fechas encontradas. 0 9 * * * da las 09:00 UTC, que la herramienta escribe como 11:00 en un navegador configurado en París el 16 de octubre de 2026. Un cron lanzado en un servidor configurado en París se dispara a las 09:00 hora de París, es decir, a las 07:00 UTC hasta el 24 de octubre y a las 08:00 UTC después. La zona que se aplica depende del sistema que ejecuta la tarea. El demonio cron sigue la zona horaria de la máquina. Un CronJob de Kubernetes sigue la del kube-controller-manager, salvo que se indique .spec.timeZone. GitHub Actions cuenta en UTC por defecto.

Leer la hora mostrada en Local como la hora a la que la tarea se ejecutará en el servidor
Olvidar que el servidor, el contenedor y tu equipo no tienen por qué compartir zona horaria
Escribir una hora local en un sistema que cuenta en UTC
Poner <code>CRON_TZ</code> o <code>TZ</code> en el campo <code>schedule</code> de un CronJob: Kubernetes rechaza el recurso, porque la zona corresponde a <code>.spec.timeZone</code> y no a ese campo
Decide la zona horaria antes de escribir la hora. Para comprobar una programación expresada en hora local, convierte la hora a UTC a mano y lee las fechas en UTC.
Dejar que una hora fija cruce un cambio de hora

Europa pasa al horario de invierno el domingo 25 de octubre de 2026. A las 03:00 hora de verano vuelven a ser las 02:00. Estados Unidos cambia una semana después, el 1 de noviembre. Una tarea fijada en 30 2 * * * se topa entonces con una hora que existe dos veces al retrasar el reloj, o que no existe al adelantarlo. Las implementaciones no coinciden. La página de manual de Debian de cron(8) indica que las tareas de la hora saltada se lanzan poco después del cambio y que las de la hora repetida no se vuelven a ejecutar. La página crontab(5) publicada en man7.org dice lo contrario. Una hora que no existe nunca coincide, y una hora repetida se dispara dos veces. GitHub Actions, con la clave timezone, adelanta una ejecución que cae en la hora saltada hasta la siguiente hora válida.

Poner una tarea importante entre las 01:00 y las 04:00 hora local
Suponer que una tarea diaria se ejecuta exactamente 24 horas después de la anterior
Contar con una sola salida cuando la hora puede jugarse dos veces o ninguna
Escribir una tarea que no soporta lanzarse dos veces
Programa en UTC cuando puedas y, si no, a una hora que siempre exista, como las 05:00, y escribe tareas que se puedan repetir sin daño.
Pegar una expresión de otro dialecto

La misma programación se escribe distinto según la herramienta. AWS EventBridge añade un campo de año y exige un ? en uno de los dos campos de día. Quartz y Spring ponen los segundos primero. El analizador rechaza lo que no conoce y nombra el campo y el token en cuestión, por ejemplo «Valor no válido en Día del mes (?)».

Pegar <code>0 0 ? * MON-FRI *</code> de EventBridge: seis campos con el ajuste en cinco y un <code>?</code> que la herramienta no lee. <code>L</code>, <code>W</code> y <code>#</code> se rechazan igual
Escribir un rango que cruza la medianoche, como <code>22-2</code>: el inicio supera al final y la herramienta lo rechaza. Escribe <code>22-23,0-2</code>
Pasar a seis campos, poner segundos distintos de cero y volver a cinco: el regreso se rechaza mientras los segundos no valgan 0
Escribir un alias fuera de la lista, como <code>@reboot</code> o <code>@every5m</code>, o usar uno en GitHub Actions, que no admite ninguno
Anota el dialecto del destino antes de copiar una expresión y convierte a mano los días, el año y los segundos. En el analizador, quédate con la forma de cinco campos.
Validar la programación y olvidar la ejecución

Una expresión correcta no garantiza que la tarea arranque, ni que arranque una sola vez. La documentación de Kubernetes avisa de que la creación de un Job es aproximada: pueden crearse dos Jobs o ninguno, y por eso las tareas deben ser idempotentes. La política de concurrencia por defecto es Allow, que deja arrancar una ejecución mientras la anterior sigue en marcha. Si el controlador cuenta más de 100 arranques perdidos, deja de lanzar la tarea y registra un error. GitHub Actions retrasa las ejecuciones programadas cuando hay mucha carga, sobre todo al comienzo de cada hora, y puede descartar alguna. En un repositorio público, los workflows programados se desactivan tras 60 días sin actividad.

Programar <code>0 * * * *</code> en GitHub Actions, donde el comienzo de la hora es el momento de mayor carga
Dejar <code>concurrencyPolicy: Allow</code> en una tarea que dura más que su intervalo
No fijar <code>startingDeadlineSeconds</code> y encontrarte, tras una caída del controlador, con más de 100 arranques perdidos y ninguna ejecución
Confiar en un workflow programado en un repositorio público que ya no recibe commits
Elige un minuto desplazado como <code>17 * * * *</code>, fija <code>concurrencyPolicy: Forbid</code> cuando dos ejecuciones no deban solaparse y añade una alerta sobre el último éxito.

Campos, alias y dialectos de un vistazo

Los cinco campos

Todos los campos aceptan los mismos operadores. Solo cambian los límites.

Minuto: de 0 a 59
Hora: de 0 a 23
Día del mes: de 1 a 31
Mes: de 1 a 12, o de JAN a DEC
Día de la semana: de 0 a 7 (0 y 7 son domingo), o de SUN a SAT
<code>*</code> designa todos los valores, <code>,</code> separa una lista, <code>-</code> traza un rango inclusivo (<code>8-11</code> da 8, 9, 10 y 11) y <code>/</code> fija un paso
Con seis campos, los segundos (de 0 a 59) van primero
Los alias

Un alias sustituye a toda la expresión. El analizador los desarrolla en el cuadro de entrada.

<code>@hourly</code> equivale a <code>0 * * * *</code>
<code>@daily</code> y <code>@midnight</code> equivalen a <code>0 0 * * *</code>
<code>@weekly</code> equivale a <code>0 0 * * 0</code>, es decir, domingo a medianoche
<code>@monthly</code> equivale a <code>0 0 1 * *</code>
<code>@yearly</code> y <code>@annually</code> equivalen a <code>0 0 1 1 *</code>
<code>@reboot</code> depende del arranque de la máquina y no tiene fecha: el analizador lo rechaza
GitHub Actions no admite ninguno de estos alias
La misma programación en cinco dialectos

Antes de copiar una expresión, comprueba qué entiende el destino.

crontab de Unix: cinco campos, en la zona horaria del sistema. Algunas implementaciones leen además una variable <code>CRON_TZ</code>
CronJob de Kubernetes: cinco campos, <code>?</code> equivale a <code>*</code>, alias admitidos. La zona se fija con <code>.spec.timeZone</code> (estable desde Kubernetes 1.27); si no, es la del kube-controller-manager
GitHub Actions: cinco campos en sintaxis POSIX, sin alias, UTC por defecto, una clave timezone opcional descrita en la documentación, un intervalo mínimo de 5 minutos y ejecución solo desde la rama por defecto
AWS EventBridge: seis campos, <code>cron(minuto hora día-del-mes mes día-de-la-semana año)</code>, con un <code>?</code> obligatorio en uno de los dos campos de día. Se permiten los operadores <code>L</code>, <code>W</code> y <code>#</code>. Las reglas programadas cuentan en UTC
Quartz y Spring: seis campos, los segundos primero
El analizador de FastMinify: cinco o seis campos (segundos primero), alias, nombres de meses y días, y nada más

El analizador cron, paso a paso

Leer una expresión

El analizador cron analiza mientras escribes, tras una breve pausa. El botón Analizar, o la tecla Intro dentro del campo, lanza el cálculo sin esperar.

1

Escribe o elige un ajuste predefinido

Seis ajustes rellenan el campo: cada 5 minutos, cada 15 minutos, cada hora, todos los días a medianoche, días laborables a las 09:00 y el día 1 de cada mes. Un alias como @daily se sustituye por su forma de cinco campos.

2

Lee la frase

Para las programaciones sencillas, una frase resume la expresión, por ejemplo «Cada 15 minutos» o «A las 09:00 en días laborables (lun–vie)». Si no, la herramienta muestra «Desglose de la programación» y te deja leer los campos.

3

Revisa las casillas

Cada casilla lleva el nombre de un campo y su valor. Aparece una nota cuando el día del mes y el día de la semana están ambos fijados, para recordar que basta con uno de los dos.

4

Lee las próximas ejecuciones

La lista da las fechas completas, con una línea «Próxima» que indica lo que falta para la primera. Aparece un aviso si no existe ninguna fecha o si la búsqueda termina antes de encontrar suficientes.

Ajustar las opciones

Tres ajustes bajo el campo de entrada cambian lo que la herramienta calcula o muestra.

1

Cinco o seis campos

Cinco campos es el ajuste inicial. Pasar a seis añade 0 al principio de la expresión, es decir, segundos a cero. Volver a cinco quita ese cero, y la herramienta lo rechaza mientras los segundos valgan algo distinto de 0.

2

Ejecuciones a mostrar

Elige 5, 10 o 25. Toma 25 para ver el patrón de un paso, de un fin de mes o de dos campos de día combinados.

3

Zona horaria

UTC es el ajuste inicial. Local usa la zona horaria de tu navegador. Una etiqueta sobre la frase recuerda la elección. El cálculo sigue en UTC en los dos casos: solo cambia cómo se escriben las fechas.

4

Copiar

Copiar descripción toma la frase, Copiar todo toma la lista, y cada línea tiene su propio botón Copiar.

Entender un rechazo

Cuando la expresión se rechaza, la herramienta explica por qué y no calcula nada.

1

Expresión vacía

Un campo que se vacía después de escribir muestra «Introduce una expresión cron».

2

Número de campos incorrecto

«Expresión cron no válida para el número de campos seleccionado» indica cuatro campos, o seis con el ajuste en cinco. Cambia el ajuste o corrige los tokens.

3

Valor no válido

Un mensaje como «Valor no válido en Hora (22-2)» nombra el campo y el token en cuestión, y la casilla de ese campo se resalta.

4

Alias no admitido

@reboot y cualquier alias fuera de la lista dan un mensaje que recuerda los que la herramienta acepta.

Las mismas programaciones en un crontab, Kubernetes, GitHub Actions y Node

Una línea de crontab

La línea se escribe en crontab -e. El comando ocupa el resto de la línea: un % sin proteger se convierte allí en un salto de línea, de ahí el \% del ejemplo (según la página de manual de crontab). Cron no ejecuta tu perfil de inicio de sesión, así que da la ruta completa de los programas.

Ejemplo básico

# m h dom mon dow command */15 9-17 * * 1-5 /usr/local/bin/sync.sh >> /var/log/sync.log 2>&1 0 2 * * * /usr/bin/tar -czf /backup/site-$(date +\%F).tar.gz /var/www # First Monday only: cron ORs day-of-month and day-of-week, so test the date in the command 0 9 * * 1 [ "$(date +\%d)" -le 7 ] && /usr/local/bin/monthly-report.sh
Un CronJob de Kubernetes

La zona horaria se declara en .spec.timeZone, nunca en schedule. Comprueba el manifiesto con el validador de Kubernetes antes de aplicarlo.

Ejemplo básico

apiVersion: batch/v1 kind: CronJob metadata: name: nightly-report spec: schedule: "0 9 * * 1-5" # five fields, no CRON_TZ or TZ prefix timeZone: "Europe/Paris" # without it, the time zone of kube-controller-manager applies concurrencyPolicy: Forbid # skip a run while the previous one is still running startingDeadlineSeconds: 300 # do not start a run more than 5 minutes late jobTemplate: spec: template: spec: restartPolicy: OnFailure containers: - name: report image: registry.example.com/report:1.4.2 command: ["/app/run-report"]
Un workflow de GitHub Actions

El workflow solo se dispara si existe en la rama por defecto. El validador de GitHub Actions comprueba el archivo, y el analizador cron las fechas.

Ejemplo básico

on: schedule: # Minute 17 avoids the busiest moment, the start of the hour. UTC by default. - cron: "17 7 * * 1-5" # Optional IANA time zone, as described in the GitHub documentation - cron: "30 5 * * 1-5" timezone: "America/New_York"
La biblioteca cron-parser con Node

Para calcular las próximas ejecuciones en una zona horaria, como hace un cron de verdad, pasa la opción tz. El ejemplo usa la versión 5 de la biblioteca. Muestra la diferencia con el analizador de FastMinify, que calcula en UTC: la misma línea da 07:00 UTC antes del 25 de octubre de 2026 y 08:00 UTC después, para una hora de París.

Ejemplo básico

import { CronExpressionParser } from 'cron-parser' // Same line, two zones: 09:00 UTC is not 09:00 in Paris const options = { currentDate: '2026-10-23T12:00:00Z', tz: 'Europe/Paris' } const paris = CronExpressionParser.parse('0 9 * * *', options) for (let i = 0; i < 3; i++) console.log(paris.next().toISOString()) // 2026-10-24T07:00:00.000Z (09:00 CEST, UTC+2) // 2026-10-25T08:00:00.000Z (09:00 CET, UTC+1: the clocks went back that night) // 2026-10-26T08:00:00.000Z const utc = CronExpressionParser.parse('0 9 * * *', { ...options, tz: 'UTC' }) console.log(utc.next().toISOString()) // 2026-10-24T09:00:00.000Z, what the parser tool shows

Conclusión

Una expresión cron cabe en cinco campos, y casi todo el error viene de lo que no se ve en ella. Un paso vuelve a empezar de cero, dos campos de día se combinan en un OR, una fecha no existe, y una zona horaria o un cambio de hora lo desplaza todo. El analizador cron pone fechas junto a la línea, y así puedes detectar estos casos antes del despliegue. Calcula en UTC, no lanza ninguna tarea y solo conoce los cinco o seis campos y los alias habituales. El destino cuenta tanto como la expresión, porque crontab, Kubernetes, GitHub Actions, EventBridge y Quartz no leen la misma sintaxis. Escribe tareas que se puedan repetir sin daño y vigila su último éxito. El hub de utilidades para desarrolladores reúne las herramientas relacionadas.

Pega la expresión en el analizador y lee las fechas además de la frase de resumen
Pide 25 ejecuciones para ver el patrón de un paso, de un fin de mes o de dos campos de día combinados
Decide la zona horaria antes de escribir la hora y escribe tareas que se puedan repetir sin daño
Evita la noche del cambio de hora y el comienzo de la hora para una tarea que importa
Anota el dialecto del destino: alias, segundos, año y zona horaria no se tratan igual en todas partes
Compartir este artículo
Compartir este artículo: