Saltar al contenido
HERRAMIENTA DEV

Convertir zona horaria cron: la hora, no la expresión

No tienes una expresión cron. Tienes un deseo: las nueve en Berlín. Eso es justo lo que se escribe aquí.

Herramienta

Casi todas las herramientas de cron dan por hecho que ya tienes la expresión y se ofrecen a explicártela. Lo normal es que no la tengas. Tienes una hora en la cabeza, una zona horaria y un patrón: días laborables a las nueve, hora de Berlín. Esta herramienta acepta exactamente eso y escribe cuatro bloques listos para pegar, para crontab, GitHub Actions, Kubernetes y AWS. Además indica la fecha en la que el próximo cambio de hora desplaza una hora cualquier línea UTC fija.

01: Cómo usarlo

¿Cómo usar esta herramienta?

  1. Escribe la hora y elige la zona horaria, por ejemplo 09:00 y Berlín.
  2. Pulsa el patrón de repetición: cada día, días laborables, cada semana en un día o cada mes en una fecha.
  3. Lee la conversión de arriba, la hora local a la izquierda y el mismo instante en UTC a la derecha, con el desfase y el día natural.
  4. Copia el bloque que necesites, cada uno viene en la sintaxis de su destino y nombra la clave que lleva la zona horaria.
  5. Lee el panel del cambio de hora antes de pegar una línea UTC fija, ahí está la fecha a partir de la cual deja de ser correcta.

¿Qué hace esta herramienta?

Invierte el sentido de entrada habitual en las herramientas de cron. El esquema de siempre es este: escribes 0 9 * * 1-5, la herramienta te dice «cada día laborable a las 09:00» y lista las próximas ejecuciones. Sirve cuando ya tienes la expresión delante, porque está en el archivo de configuración de otra persona. Cuando escribes un job nuevo, no la tienes. Tienes una hora en la cabeza.

Así que aquí la hora es la entrada. Escribes 09:00, eliges Berlín, pulsas «días laborables» y recibes cuatro bloques terminados: la línea para crontab -e, el bloque schedule de un archivo de GitHub Actions, un manifiesto CronJob de Kubernetes completo y el comando de AWS EventBridge Scheduler. Cada bloque lleva la clave con la que su destino guarda la zona horaria y, debajo, el mismo instante como línea UTC fija, para entornos que no conocen esa clave.

Todo se calcula en el navegador. Nada de lo que escribes se envía a ningún sitio y no hay cuentas.

¿Por qué la zona horaria da tantos problemas en cron?

Porque cron no tiene ninguna. Los cinco campos de una expresión guardan minuto, hora, día del mes, mes y día de la semana, y en ningún sitio una zona. Qué reloj se aplica lo decide aquello que evalúa la línea. En un servidor es su hora del sistema, en un contenedor suele ser UTC, en una plataforma gestionada es lo que haya decidido el proveedor.

De ahí sale un fallo que nadie detecta al escribirlo. La línea es sintácticamente correcta, se acepta, el job se ejecuta, no aparece ningún error. Simplemente se ejecuta a la hora equivocada. Y como lo hace de forma fiable, muchas veces solo sale a la luz cuando alguien pregunta por qué el informe ya está en su bandeja a las siete.

La segunda mitad del problema es el horario de verano. Aunque conviertas bien, tu cuenta solo vale hasta el siguiente cambio. Las 09:00 de Berlín son las 07:00 UTC en verano y las 08:00 UTC en invierno. Si escribes una línea UTC en agosto, a partir del 25 de octubre de 2026 está una hora desviada sin que se rompa nada que te avise. En la UE, la supresión del cambio de hora lleva años parada porque los estados miembros no se ponen de acuerdo sobre qué hora fija adoptar, así que el asunto seguirá aquí una temporada.

¿Qué claves de zona horaria existen?

Los cuatro destinos ya pueden llevar la zona dentro. Lo que pasa es que cada uno la llama de otra forma, y por eso hay gente que sigue convirtiendo a mano cuando ya no hace falta.

Destino Clave Disponible desde
crontab (cronie, Vixie) CRON_TZ=Europe/Berlin Vixie cron 4.0
GitHub Actions timezone: "Europe/Berlin" Marzo de 2026
Kubernetes CronJob spec.timeZone Kubernetes 1.27
AWS EventBridge Scheduler --schedule-expression-timezone Noviembre de 2022
Timers de systemd OnCalendar=... Europe/Berlin systemd 242

La tabla tiene un rezagado y un hueco. El rezagado es GitHub Actions: hasta marzo de 2026 el bloque schedule solo entendía UTC, y entonces llegó la clave timezone. La documentación de GitHub ya la muestra como un ejemplo normal. Como el cambio es reciente, muchos tutoriales, respuestas antiguas de foros y varias herramientas de la competencia siguen diciendo que Actions es solo UTC. Ya no es cierto.

El hueco son las reglas clásicas de EventBridge. A diferencia de Scheduler no tienen parámetro de zona, y AWS las lista en su propia documentación como funcionalidad heredada con un aviso hacia Scheduler. Si sigues usándolas, no te libras de la línea UTC fija, y a esa sí le aplica el panel del cambio de hora.

¿Por qué se desplaza el día de la semana?

Este es el error que más tiempo pasa desapercibido, porque solo aparece con determinadas zonas y, cuando aparece, lo hace cada semana.

Toma las 06:00 de un lunes en Tokio. Tokio va nueve horas por delante de UTC, así que son las 21:00 UTC. Pero del domingo, no del lunes. Si conviertes la hora y dejas el 1 de lunes en el campo del día de la semana, obtienes 0 21 * * 1, que lanza el job todos los lunes por la noche, 24 horas después del momento que querías. Lo correcto es 0 21 * * 0.

La misma trampa en sentido contrario: las 20:00 de un viernes en Nueva York son las 00:00 UTC del sábado. Las zonas con media hora lo agravan, porque ahí tampoco puede quedarse quieto el campo de minutos. Las 09:00 de Calcuta son las 03:30 UTC, no las 03:00, porque India va cinco horas y media por delante. Nepal está en UTC+5:45 y las islas Chatham en UTC+12:45.

La herramienta desplaza el día de la semana y el campo de minutos. En un patrón mensual desplaza también el día del mes mientras sea posible, y te avisa cuando no lo es. El día 1 de un mes no puede retroceder una jornada: «el último día del mes anterior» no es un número fijo que quepa en el campo de día.

¿Cuándo se desvía exactamente mi línea UTC fija?

Justo cuando la zona elegida cambia el reloj. La herramienta busca esa fecha en la base de datos de zonas horarias que tu navegador ya lleva dentro y la nombra, junto con el sentido, la cantidad y la hora a la que la línea acabará ejecutándose.

Las próximas fechas están más juntas de lo que parece y no todas las zonas se mueven a la vez. Sídney adelanta el 4 de octubre de 2026, porque en el hemisferio sur el horario de verano empieza entonces. Berlín atrasa el 25 de octubre de 2026. Nueva York va una semana después, el 1 de noviembre de 2026, porque Estados Unidos sigue su propia regla. Si programas jobs en varias regiones, tienes tres fechas distintas en cinco semanas.

Algunas zonas no se mueven nunca. Calcuta se queda todo el año en UTC+5:30, Tokio en UTC+9 y São Paulo suprimió el horario de verano hace años. Para esas la herramienta lo dice explícitamente en lugar de mostrar un aviso que no aplica. Allí una línea UTC fija es correcta de forma permanente.

¿Qué hago contra el desplazamiento?

Cuatro caminos, en el orden en que compensan.

El primero es la clave de la tabla de arriba. Si tu destino la admite, el problema no existe, porque el sistema calcula el horario de verano por su cuenta. Por eso los cuatro bloques de la herramienta llevan la zona incorporada y no muestran la línea convertida.

El segundo es cambiar de destino. Una regla clásica de EventBridge se sustituye por una entrada de Scheduler, y un contenedor busybox por una imagen base con cronie. Ambas cosas son trabajo de una vez en lugar de trabajo dos veces al año.

El tercero es trabajo manual con recordatorio. Si la línea tiene que quedarse fija, apunta la fecha del panel en el calendario y ajusta ahí la hora. Funciona mientras alguien se sienta responsable.

El cuarto es asumir el desplazamiento a propósito. Un job nocturno de limpieza que en invierno se ejecute a las dos en vez de a las tres no molesta a nadie. Es una decisión perfectamente válida, solo que tiene que ser una decisión y no una sorpresa en noviembre.

¿Y la puntualidad en sí?

Un punto que no tiene nada que ver con las zonas horarias pero genera las mismas quejas: las ejecuciones programadas de GitHub Actions arrancan tarde con frecuencia. GitHub no garantiza el minuto y, en las horas en punto, cuando vencen muchas planificaciones a la vez, la cola se acumula.

Conviene saberlo antes de culpar a la conversión. Si tu job se ejecuta cuatro horas tarde, no es la zona horaria, porque una zona desplaza una hora entera o media, nunca cuatro. Si en cambio tu job está siempre exactamente una hora desviado, casi siempre es la zona o el horario de verano. La magnitud del error ya te dice dónde mirar.

¿Mi expresión necesita de verdad una zona horaria?

No siempre. Si tu job tiene que ejecutarse a una hora fija que alguien ve, o sea un informe al empezar la jornada, un cierre al terminar el negocio, un recordatorio por la mañana, entonces sí. Esas horas están atadas a un reloj local y una hora de desvío se nota.

Si tu job solo tiene que ejecutarse con regularidad, o sea limpiar cada 15 minutos, refrescar una caché cada hora, respaldar algo en algún momento de la noche, entonces no. Para esos casos UTC es la opción más sencilla, porque nunca cambia y te ahorras la pregunta entera. El generador de expresiones cron encaja mejor ahí: escribes la expresión directamente y te la explica.

La regla práctica: si la hora está atada a una persona, necesitas una zona. Si solo está atada a un intervalo, no.

Última actualización:

También le puede interesar