Parser de expresiones Cron explicado para no-DevOps (2026)
Parser de expresiones Cron explicado para no-DevOps
Heredas un proyecto, abres su YAML de Kubernetes y ves esto:
schedule: "0 */6 * * 1-5"
¿Eso es "cada 6 horas en días entre semana" o "a la medianoche y al mediodía los lunes"? ¿Cuándo correrá realmente la próxima vez? ¿Se atrasará una hora durante daylight saving? La sintaxis cron es densa, ambigua sin documentación, y un puñado de surpresas legendarias acechan en su esquina — particularmente alrededor de los modificadores ?, day-of-week vs day-of-month y zonas horarias.
Esta guía explica los 5 campos de una expresión cron, los modificadores especiales que ahorran tiempo y los puntos de tropiezo comunes. También cubrimos cómo usar el parser cron de Ai2Done para verificar cualquier expresión que escribas y ver sus próximas 10 ejecuciones antes de hacer deploy a producción.
TL;DR
- Una expresión cron tiene 5 campos: minuto, hora, día-del-mes, mes, día-de-la-semana.
- Cada campo acepta
*(cualquiera), un número (5), una lista (1,15,30), un rango (9-17) o un paso (*/15). */15 * * * *corre cada 15 minutos del reloj — 00, 15, 30, 45 — no cada 15 minutos desde un punto de partida arbitrario.- Especificar tanto día-del-mes como día-de-la-semana se comporta diferente entre Linux cron (OR) y Quartz (AND). Esto es la causa #1 de tareas cron silenciosamente nunca corriendo.
- Verifica siempre tu expresión con el parser cron de Ai2Done — muestra próximas 10 ejecuciones y explica la expresión en inglés llano antes de comprometerte.
La sintaxis básica de 5 campos
* * * * *
│ │ │ │ │
│ │ │ │ └── día de la semana (0-6, dom=0)
│ │ │ └─────── mes (1-12)
│ │ └──────────── día del mes (1-31)
│ └───────────────── hora (0-23)
└────────────────────── minuto (0-59)
Lee de izquierda a derecha: minuto, hora, día-del-mes, mes, día-de-la-semana.
Ejemplos comunes:
| Expresión | Significado en lenguaje natural |
|---|---|
* * * * * |
Cada minuto |
0 * * * * |
Al minuto 0 de cada hora (al inicio de cada hora) |
0 0 * * * |
A medianoche cada día |
0 9 * * 1-5 |
A las 9:00 AM, lunes a viernes |
*/15 * * * * |
Cada 15 minutos (00, 15, 30, 45) |
0 */6 * * * |
Cada 6 horas (00:00, 06:00, 12:00, 18:00) |
0 0 1 * * |
A medianoche el primero de cada mes |
0 0 * * 0 |
A medianoche cada domingo |
30 8 1 * * |
A las 8:30 AM el primero de cada mes |
0 22 * * 1-5 |
A las 22:00 (10 PM), lunes a viernes |
0 0 1 1 * |
Una vez al año a medianoche del 1 de enero |
Los modificadores especiales
* (asterisco) = cualquier valor. * * * * * corre cada minuto.
, (coma) = lista. 0 9,12,18 * * * corre a las 9 AM, 12 PM y 6 PM.
- (guion) = rango. 0 9-17 * * * corre cada hora de 9 AM a 5 PM (inclusive).
/ (slash) = paso. */15 * * * * corre cada 15 minutos. 0 */6 * * * corre cada 6 horas.
Combinaciones funcionan: 0 9-17/2 * * 1-5 corre cada 2 horas de 9 AM a 5 PM, lunes a viernes (9, 11, 13, 15, 17).
Las tres maldiciones cron
Maldición #1: */15 no significa "cada 15 minutos desde ahora"
Un error común: pones */15 * * * * pensando "corre cada 15 minutos". Lo que realmente hace es corre cuando minute % 15 == 0, p. ej. en 00, 15, 30, 45 del reloj. Si haces deploy a las 14:07, tu trabajo corre a 14:15, no a 14:22.
Esto importa cuando piensas en distribución de carga — si 100 servidores tienen */15 * * * *, los 100 disparan exactamente en :00, :15, :30, :45, no escalonados. Para escalonar, dale a cada servidor un minute offset diferente: 7 */15 * * *, 12 */15 * * *, etc.
Maldición #2: Day-of-month + Day-of-week es OR (Linux) o AND (Quartz)
Esta es la trampa más cara en cron. Considera:
0 9 15 * 1
Lectura ingenua: "a las 9 AM el día 15 del mes Y que también sea lunes". Eso casi nunca corre.
Realidad en Linux cron (vixie-cron, anacron, BSD cron): el campo day-of-month y day-of-week se OR-ean juntos cuando ambos son no-*. La expresión arriba corre a las 9 AM cada día 15 del mes O cualquier lunes — eso son ~5+ ejecuciones por mes.
Realidad en Quartz (Java, Spring, Jenkins): el comportamiento por defecto AND-ea los dos. Misma expresión raramente corre — solo cuando el 15 cae en lunes.
El fix: usa ? (cuando esté soportado) para significar "no me importa este campo". En Quartz: 0 9 15 * ? corre a las 9 AM del día 15 sin importar el día de la semana. En cron de Linux: usa * para uno y un valor específico para el otro, nunca ambos no-* a menos que realmente quieras el OR.
Esto es responsable de probablemente el 30 % de los Q&A "mi cron no está corriendo" en Stack Overflow.
Maldición #3: Las zonas horarias y DST muerden
cron (el daemon Linux) corre en la hora local del servidor por defecto. Si tu servidor está en UTC y tú estás en Madrid, tu trabajo "9 AM" corre a las 11 AM tu hora.
Peor: durante daylight saving en zonas que la observan, las 2:00-3:00 AM hora local se omite cada primavera (los relojes saltan adelante) y se ejecuta dos veces cada otoño (los relojes retroceden). Un trabajo programado para 30 2 * * * correrá cero veces ese día de marzo y dos veces ese día de octubre.
Best practice moderna: corre cron jobs en UTC siempre, convierte a hora local en application logic si los humanos necesitan ver la programación. Kubernetes CronJobs por defecto a UTC. Esto evita silenciosamente las maldiciones DST.
Método 1: Ai2Done cron parser (lado del navegador)
El parser cron de Ai2Done está diseñado específicamente para "escribí esta expresión, ¿hace lo que creo?":
- Abre /tools/cron_parser en cualquier navegador.
- Pega o teclea tu expresión cron — soportamos sintaxis estándar Linux cron, atajos como
@dailyy@hourly, y la extensión Quartz?. - La explicación aparece instantáneamente en inglés llano — p. ej.
0 */6 * * 1-5se convierte en "At minute 0, every 6 hours, Monday through Friday". - Las próximas 10 ejecuciones se listan con timestamps absolutos, en UTC y en tu zona horaria local lado a lado.
- El badge de validación te dice si la expresión es válida o exactamente qué está mal (p. ej. "El campo 5 espera 0-6, recibió 7").
Sin signup, sin recolección de datos. La expresión nunca sale de tu navegador.
Esto es de uso diario para los developers que mantienen un piloto automático grande de cron — peg ualquier expresión que veas en un PR, confirma que coincide con la intención, ahorra los 20 minutos de mental-arithmetic-then-deploy-then-find-out-tomorrow.
Método 2: crontab.guru y herramientas similares
crontab.guru es la herramienta de cron-explainer más cariñosamente recordada, gratis online desde ~2014. UI más pequeña que la nuestra, sin previewing batch, sin manejo de zona horaria, sin export — pero hace una cosa bien (explicar una expresión) y la hace simple.
cronstrue es la librería JavaScript subyacente que la mayoría de los explainers cron online (incluida la nuestra) usa para la traducción a inglés. Es excelente para usar en tu propia herramienta interna si construyes un dashboard de admin que necesita mostrar programaciones legibles por humanos.
Método 3: cron-parser en Node.js
Para uso programático — validando expresiones en CI o calculando próximas ejecuciones en código de aplicación:
import parser from 'cron-parser';
const interval = parser.parseExpression('0 */6 * * 1-5');
console.log('Next:', interval.next().toString());
console.log('Next:', interval.next().toString());
console.log('Next:', interval.next().toString());
cron-parser maneja zonas horarias, modificadores Quartz y números de DST correctamente. Esta es la librería de elección para cualquier sistema que necesita computar "cuándo es la próxima ejecución de esta expresión" en lógica del servidor.
Cómo construimos el parser (deep-dive técnico)
El parser cron de Ai2Done está construido sobre dos librerías open-source:
cronstruepara traducción de expresión a inglés (probada en batalla, ~5 años de pulido)cron-parserpara computar próximas ejecuciones (maneja DST, modificadores Quartz, atajos@daily)
Sobre esto añadimos:
- Validación per-campo. Si tecleas
60 * * * *(60 minutos no es válido — el rango es 0-59) resaltamos el campo en rojo y mostramos "Expected 0-59, got 60". La mayoría de los parsers cron solo dicen "syntax error" sin decirte dónde. - Conciencia de zona horaria. Cada timestamp se renderiza dos veces — en UTC y en tu zona horaria local del navegador. Para programación cross-team, esto es la diferencia entre "todos saben cuándo corre" y "alguien pierde una hora durante DST".
- Confianza de explicación. Si la expresión usa formas potencialmente ambiguas (como ambos día-del-mes y día-de-la-semana no-
*), mostramos un warning amarillo explicando el comportamiento Linux-OR-vs-Quartz-AND, en vez de adivinar silenciosamente uno u otro. - Soporte de presets. Botones de un-clic para programaciones comunes — "Daily at midnight UTC", "Hourly", "Weekdays at 9 AM local", "First of every month" — porque para 80 % de los casos de uso, no necesitas escribir cron a mano.
Toda la herramienta es ~80 KB gzipped y carga instantáneamente. Sin llamadas server-side jamás.
FAQ
Q: ¿Por qué mi cron job no está corriendo?
A: Las causas más probables, en orden: (1) ambos día-del-mes y día-de-la-semana no-* con motor que las AND-ea, (2) zona horaria mismatch (tu servidor está en UTC, tu intención fue hora local), (3) jitter DST (el reloj saltó), (4) el comando mismo está fallando silenciosamente (revisa stderr/exit code). Verifica con nuestro parser primero — si las próximas 10 ejecuciones se ven correctas, el problema está en el ejecutor de comando, no en la programación.
Q: ¿Qué es @daily y otros atajos?
A: Linux cron y la mayoría de los motores cron entienden estos atajos: @yearly (= 0 0 1 1 *), @monthly (= 0 0 1 * *), @weekly (= 0 0 * * 0), @daily (= 0 0 * * *) y @hourly (= 0 * * * *). También @reboot corre una vez al boot del sistema (sin equivalente cron-syntax).
Q: ¿Cuál es la diferencia entre Linux cron y Quartz cron?
A: Linux cron tiene 5 campos. Quartz cron (usado en Java, Spring, Jenkins, Hangfire) tiene 6 o 7 campos — añade segundos al principio y opcionalmente año al final. Quartz también soporta ? (no-care) y L (last) y W (weekday) y # (nth weekday). Nuestro parser detecta cuál estás usando automáticamente basado en el conteo de campos.
Q: ¿Puedo hacer cron correr a las 2:30 AM, 7:15 AM y 8:45 PM? A: Múltiples horas no-alineadas no encajan en una sola expresión cron limpiamente. Usa tres líneas crontab o tres CronJobs Kubernetes — uno por programación. O usa un scheduler como systemd timers que soporta listas más expresivas.
Q: ¿Cómo hago algo "cada 90 minutos"?
A: No puedes con cron solo. Cron es relativa al reloj de pared, no relativa a la última ejecución. Para intervalos verdaderos como 90 minutos o 4 horas y 15 minutos, usa systemd timers (OnUnitActiveSec=90min) o programación a nivel app (un setTimeout en bucle).
Q: ¿Cron jobs corren si mi servidor estaba dormido / apagado?
A: Vanilla cron, no — si el servidor estaba abajo a la hora programada, esa ejecución se omite. anacron (común en distros desktop) recoge ejecuciones perdidas al boot. systemd timers con Persistent=true hacen lo mismo. Kubernetes CronJobs tienen startingDeadlineSeconds para política de catch-up.
Pruébalo ahora
Verifica cualquier expresión cron antes de hacer deploy:
Pega tu expresión, ve la explicación en inglés llano y las próximas 10 ejecuciones en tu zona horaria local. Sin signup.
Lecturas relacionadas
- Toolbox JSON, YAML, XML, CSV — para los archivos config donde aterrizan las expresiones cron
- Decodificador JSON Web Token que nunca envía tu token — otra herramienta dev del lado del navegador
- Overview de todas las herramientas Ai2Done
- Explora el hub de herramientas para developer
Última actualización 2026-06-14. El parser cron corre 100 % en tu navegador. Nunca recopilamos, logueamos ni analizamos las expresiones que pegas.