Cómo utilizar el generador y explicador de Cron
- Seleccionar el dialecto de programación: Elija el formato POSIX crontab estándar de 5 campos (a nivel de minuto) para servidores Linux, o Spring/Quartz de 6 campos (a nivel de segundo) para aplicaciones empresariales.
- Definir los valores de cada campo: Utilice las pestañas interactivas para configurar intervalos cíclicos, rangos continuos o selecciones puntuales. También puede escribir o pegar directamente cualquier expresión en la barra superior para su análisis inmediato.
- Verificar la interpretación en lenguaje natural: Compruebe que la explicación en lenguaje natural generada coincida exactamente con la planificación operativa deseada sin ambigüedad lógica.
- Inspeccionar las próximas ejecuciones calculadas: Audite las próximas 6 ejecuciones en tiempo local del navegador o en UTC para comprobar los ciclos de repetición y el avance de fechas.
- Desplegar la configuración en producción: Copie la expresión cron validada u obtenga fragmentos listos para entornos de producción en Linux Crontab, Kubernetes, systemd, Node.js, Python o Go.
Comparativa de dialectos Cron: POSIX de 5 campos frente a motores de aplicación de 6 campos
Los distintos entornos de ejecución presentan especificaciones divergentes en la numeración de índices, el valor asignado al domingo y la lógica entre campos de día. Seleccionar un dialecto erróneo provoca desfases silenciosos de programación:
| Dialecto / Motor | Estructura de campos | Segundos (subminuto) | Índice del domingo | Lógica DOM / DOW | Ecosistema principal |
|---|---|---|---|---|---|
| POSIX / Linux Crontab | 5 campos (Min, Hora, DOM, Mes, DOW) | No (mínimo 1 minuto) | 0 = Dom, 6 = Sáb (7 también = Dom) | Evaluación lógica OR cuando ninguno es * | cron, cronie, busybox, crond, crontabs del sistema |
| Spring Boot (@Scheduled) | 6 campos (Seg, Min, Hora, DOM, Mes, DOW) | Sí (mínimo 1 segundo) | 0 o 7 = Dom, 1 = Lun ... 6 = Sáb | Admite ? para resolver ambigüedades | Spring Framework, Micronaut, Quarkus |
| Quartz Scheduler | 6–7 campos (Seg, Min, Hora, DOM, Mes, DOW, [Año]) | Sí (mínimo 1 segundo) | 1 = Dom, 2 = Lun ... 7 = Sáb | ? obligatorio en DOM o DOW | Java Quartz, Apache Camel, Camunda |
| AWS EventBridge / CloudWatch | 6 campos (Min, Hora, DOM, Mes, DOW, Año) | No | 1 = Dom, 2 = Lun ... 7 = Sáb | ? obligatorio en DOM o DOW | Desencadenadores de AWS Lambda, reglas de EventBridge |
| Kubernetes CronJob | 5 campos (Min, Hora, DOM, Mes, DOW) | No | 0–7 = Dom (compatible con POSIX) | Evaluación lógica OR (estándar POSIX) | Kube-controller-manager, k8s batch/v1 |
Arquitectura posicional de los campos y límites de valor
Los componentes de una expresión cron se evalúan de izquierda a derecha como filtros sucesivos de tiempo. El demonio inicia la ejecución cuando el reloj del sistema satisface simultáneamente todas las posiciones configuradas:
| Posición | Nombre del campo | Rango de valores | Operadores | Ejemplo | Comportamiento de evaluación |
|---|---|---|---|---|---|
| #1 (Quartz/Spring) | Segundo | 0 – 59 | * , - / | */10 | Activador con precisión de subminuto. Ausente en crontab POSIX estándar de 5 campos. |
| #1 (POSIX) / #2 | Minuto | 0 – 59 | * , - / | 0,15,30,45 | Minuto dentro de la hora. Granularidad básica para los demonios cron de Linux. |
| #2 (POSIX) / #3 | Hora | 0 – 23 | * , - / | 2-4 | Notación militar de 24 horas. 0 representa la medianoche, 23 representa las 23:00. |
| #3 (POSIX) / #4 | Día del mes | 1 – 31 | * , - / ? L W | L | Día del mes calendario. Limitado por la duración del mes (28–31 días). Se evalúa con lógica OR junto al día de la semana. |
| #4 (POSIX) / #5 | Mes | 1 – 12 / JAN – DEC | * , - / | */3 | Mes del calendario. Los alias de texto (JAN–DEC) no distinguen entre mayúsculas y minúsculas. |
| #5 (POSIX) / #6 | Día de la semana | 0 – 7 / SUN – SAT | * , - / ? L # | 1-5 | Día en el ciclo semanal. POSIX considera 0 y 7 como domingo; Quartz considera 1 como domingo. |
Sintaxis de caracteres especiales y semántica de operadores
Comodín (todos los valores)
Coincide con todos los enteros válidos dentro del rango del campo correspondiente.
Intervalo de paso
Aplica incrementos a partir de un valor base (base/paso).
Conjunto discreto (lista)
Combina valores discretos no consecutivos en un conjunto de ejecución explícito.
Rango continuo
Define un intervalo numérico cerrado e inclusivo [inicio, fin].
Carácter no restringido
Requerido por Quartz y AWS cuando uno de los campos de día (día del mes o de la semana) no impone restricciones.
Última repetición (Last)
Especifica el último día del mes o el último día de la semana específico (p. ej., 5L = último viernes).
Día laborable más cercano (Weekday)
Ajusta la ejecución al día laborable (lunes a viernes) más cercano a la fecha indicada.
Enésimo día de la semana
Indica la enésima aparición de un día de la semana en el mes (día#aparición).
Patrones de fallo habituales en producción y mitigaciones de ingeniería
1. La trampa del OR lógico entre DOM y DOW
POSIX IEEE 1003.1En el crontab estándar, cuando tanto el Día del mes como el Día de la semana no son asteriscos, se evalúan mediante un OR lógico, no un AND. La expresión 0 2 15 * 5 se activará cada día 15 del mes Y también cada viernes a lo largo del mes.
0 2 15 * * [ $(date +\%u) -eq 5 ] && /opt/scripts/tarea.sh
2. Desfases por Horario de Verano (DST)
Anomalía del reloj del sistemaCuando los relojes se adelantan (02:00 -> 03:00), las tareas programadas entre las 02:00 y las 02:59 son omitidas por completo en Vixie cron. Cuando se atrasan (02:00 -> 01:00), las tareas programadas entre las 01:00 y las 01:59 se ejecutan dos veces.
timedatectl set-timezone UTC
3. Sobrecarga de tareas y cascada de ejecuciones
Fallo por concurrencia descontroladaLos demonios cron lanzan procesos sin verificar si la ejecución anterior ha concluido. Si un proceso de 1 minuto tarda 90 segundos por bloqueos en bases de datos, se generará una segunda instancia en paralelo, saturando los recursos hasta provocar errores OOM.
* * * * * /usr/bin/flock -n /var/lock/worker.lock /usr/bin/worker
4. Truncamiento en el reinicio del intervalo de paso
Caso de borde por móduloLos valores de paso no funcionan como temporizadores deslizantes continuos. En minutos, */7 calcula coincidencias por módulo dentro de [0, 59], ejecutándose en 0, 7, 14, 21, 28, 35, 42, 49 y 56. La siguiente ejecución será en el minuto 0 de la hora posterior, generando un salto de apenas 4 minutos en lugar de 7.
OnUnitActiveSec=7m
Comparativa de plataformas de infraestructura de programación
| Plataforma | Resolución | Control de solapamiento | Gestión de ejecuciones perdidas | Telemetría y registros | Contexto de zona horaria |
|---|---|---|---|---|---|
| Linux Vixie / cronie | 1 minuto | Ninguno (requiere bloqueo explícito con flock) | Se omite por completo | syslog / journald (/var/log/cron) | Reloj del sistema del servidor (/etc/localtime) |
| Systemd Timers | 1 microsegundo | Integrado (cola con Type=oneshot) | Persistent=true ejecuta tareas perdidas tras reiniciar | journalctl -u nombre-servicio | Admite directivas explícitas de zona horaria |
| Kubernetes CronJob | 1 minuto | concurrencyPolicy (Allow / Forbid / Replace) | Evaluación con startingDeadlineSeconds | kubectl logs nombre-pod | timeZone en la especificación (k8s 1.27+; UTC por defecto) |
| AWS EventBridge | 1 minuto | Limitación gestionada de destino y cola de mensajes no enviados (DLQ) | Reintento automático con retroceso exponencial | Métricas y registros en AWS CloudWatch | Estándar estricto en UTC |
Guía de referencia rápida de expresiones Cron probadas en producción
| Nivel operativo | Frecuencia deseada | Expresión Cron | Dialecto | Comportamiento de ejecución |
|---|---|---|---|---|
| Telemetría y alta frecuencia | Cada 10 segundos | */10 * * * * ? | Quartz (6 campos) | Sondeo de telemetría subminuto, refresco de caché o latido heartbeat. |
| Sondeo y vaciado de colas | Cada 5 minutos | */5 * * * * | POSIX (5 campos) | Se activa en los minutos 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 y 55. |
| Métricas y agregaciones | Cada hora en punto | 0 * * * * | POSIX (5 campos) | Se ejecuta cada hora en punto (xx:00:00). |
| Mantenimiento y copias frías | Diariamente a las 02:00 | 0 2 * * * | POSIX (5 campos) | Ventana nocturna habitual para VACUUM de bases de datos, copias de seguridad y rotación de registros. |
| Automatización laboral | Lunes a viernes a las 09:00 | 0 9 * * 1-5 | POSIX (5 campos) | Se ejecuta únicamente en días laborables; omite sábados y domingos. |
| Reindexación semanal | Cada domingo a medianoche | 0 0 * * 0 | POSIX (5 campos) | Resúmenes contables semanales, reindexación de bases de datos y limpieza de almacenamiento. |
| Facturación mensual | Día 1 de cada mes a las 00:00 | 0 0 1 * * | POSIX (5 campos) | Se ejecuta el primer día calendario de cada mes a medianoche. |
| Cierres trimestrales | Día 1 de ene, abr, jul, oct | 0 0 1 1,4,7,10 * | POSIX (5 campos) | Balances financieros trimestrales, sincronizaciones fiscales y auditorías periódicas. |
Configuraciones de producción y fragmentos en múltiples lenguajes
# Declaración explícita de entorno, bloqueo sin espera y registro combinado
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 2 * * * /usr/bin/flock -n /var/lock/db_backup.lock /opt/scripts/backup.sh >> /var/log/backup.log 2>&1apiVersion: batch/v1
kind: CronJob
metadata:
name: telemetry-sync
spec:
schedule: "*/15 * * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: sync-worker
image: registry.example.com/worker:v1.4
restartPolicy: OnFailureimport cron from 'node-cron';
// Programación de tarea con zona horaria IANA para evitar desfases del reloj anfitrión
cron.schedule('0 9 * * 1-5', () => {
console.log('Ejecutando proceso laboral matutino');
}, {
scheduled: true,
timezone: 'America/Mexico_City'
});from datetime import datetime, timezone
from croniter import croniter
base_time = datetime.now(timezone.utc)
iter = croniter('0 2 * * *', base_time)
# Calcular las siguientes 3 marcas de tiempo de ejecución
for _ in range(3):
next_run = iter.get_next(datetime)
print(f"Próxima ejecución en UTC: {next_run.isoformat()}")package main
import (
"fmt"
"github.com/robfig/cron/v3"
)
func main() {
// Analizador estándar de 5 campos sin segundos
c := cron.New()
_, err := c.AddFunc("0 0 1 * *", func() {
fmt.Println("Ejecutando conciliación contable mensual")
})
if err != nil {
panic(err)
}
c.Start()
select {}
}import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTasks {
// Formato de 6 campos de Spring: Segundo Minuto Hora Día Mes DíaSemana
@Scheduled(cron = "0 0 2 * * ?", zone = "UTC")
public void executeNightlyBatch() {
// Ejecución de la lógica de negocio
}
}Preguntas frecuentes sobre expresiones Cron
¿Cuál es la diferencia funcional entre Crontab de 5 campos y Spring/Quartz de 6 campos?
El Crontab estándar de Linux utiliza 5 campos delimitados por espacios que comienzan con Minuto (0-59), ofreciendo una granularidad mínima de 1 minuto. Spring Boot y Quartz anteponen un campo de Segundos (0-59) en la primera posición, lo que permite programar tareas con resolución de submuto. Además, Quartz exige el uso del signo de interrogación (?) en el Día del mes o en el Día de la semana cuando ese campo no tiene restricciones, evitando así reglas contradictorias.
¿Por qué "0 2 15 * 5" se ejecuta en días que no son viernes 15?
Según la especificación IEEE 1003.1 (POSIX), cuando tanto el Día del mes como el Día de la semana están explícitamente restringidos (ninguno es *), el planificador los evalúa con una operación lógica OR en lugar de un AND. La tarea se ejecutará cada vez que el día sea el 15 del mes O el día sea viernes. Para imponer una condición AND estricta en Linux, fije el Día de la semana en * y verifique el día en la orden de shell: 0 2 15 * * [ $(date +\%u) -eq 5 ] && /opt/scripts/tarea.sh.
¿Cómo evitar el solapamiento de procesos cuando una tarea cron tarda más que su intervalo de ejecución?
Los demonios cron tradicionales no supervisan la finalización de los procesos. Si una tarea programada cada minuto demora 90 segundos, se iniciará una segunda instancia en paralelo. En Linux, evite este problema utilizando bloqueos de archivo no bloqueantes mediante flock: * * * * * /usr/bin/flock -n /var/lock/mitarea.lock /opt/scripts/mitarea.sh. En Kubernetes, defina concurrencyPolicy: Forbid en el manifiesto del CronJob.
¿Cómo funciona la sintaxis de paso (*/N) cuando el límite del campo no es divisible exactamente?
Las expresiones de paso calculan las repeticiones sumando N al valor base dentro de los límites del campo. Por ejemplo, */7 en el campo de minutos se activa en 0, 7, 14, 21, 28, 35, 42, 49 y 56. Al cambiar de hora, la secuencia se reinicia en 0. En consecuencia, el intervalo entre el minuto 56 y el minuto 0 de la hora siguiente es de solo 4 minutos, no de 7.
¿Cómo programar una tarea el último día del mes en Crontab de 5 campos sin el modificador "L" de Quartz?
El crontab POSIX carece del modificador L. Para ejecutar un comando el último día calendario de cualquier mes (tenga 28, 29, 30 o 31 días), programe la tarea para los días 28 a 31 y compruebe en shell si el día siguiente es el 1 del mes entrante: 59 23 28-31 * * [ $(date -d tomorrow +\%d) -eq 1 ] && /opt/scripts/fin_de_mes.sh.
¿Se evalúan las expresiones Cron en UTC o en la hora local del servidor, y cómo influye el horario de verano (DST)?
Linux crontab se rige por el reloj del sistema configurado en /etc/localtime. Cuando se produce el cambio de hora hacia adelante en primavera (02:00 -> 03:00), las tareas programadas entre las 02:00 y las 02:59 se omiten por completo en Vixie cron. Al retrasar el reloj en otoño (02:00 -> 01:00), las tareas programadas entre las 01:00 y las 01:59 se ejecutan dos veces. Las infraestructuras de producción modernas (Kubernetes, AWS EventBridge, GitHub Actions) operan exclusivamente en UTC para eliminar estos desfases.
¿Por qué las tareas programadas con Cron fallan frecuentemente por variables de entorno o errores de ruta (PATH)?
Los demonios cron ejecutan comandos en un entorno de shell POSIX sumamente reducido, que generalmente solo define HOME, LOGNAME y un PATH mínimo (/usr/bin:/bin). Las variables definidas por el usuario en ~/.bashrc o ~/.zshrc no se cargan. Utilice siempre rutas absolutas para los ejecutables (/usr/bin/node en lugar de node) y redirija explícitamente tanto la salida estándar como la de errores: >> /var/log/mitarea.log 2>&1.
¿Cuándo es preferible utilizar temporizadores de systemd (systemd timers) en lugar del crontab tradicional?
Los temporizadores de systemd superan a crontab en entornos Linux cuando se necesita precisión de submuto, temporizadores monotónicos (por ejemplo, OnUnitActiveSec=15m tras la finalización previa para prevenir solapamientos de forma nativa), recuperación automática de tareas perdidas tras reiniciar el servidor (Persistent=true), aislamiento de recursos con cgroups y registro unificado mediante journalctl.
