¿Por qué mi contenedor Docker tiene la hora equivocada?
Cristian Tafur
@Cristia16195614Programas una tarea para la noche y arranca en plena tarde. En los registros todas las horas van cinco horas adelantadas: tu equipo marca bien la hora, el contenedor no.
Un contenedor no hereda la zona horaria del equipo anfitrión; si no le indicas otra, trabaja en UTC.
Comprueba la hora dentro del contenedor
Compara la hora de tu equipo con la del contenedor:
date
docker exec mi-contenedor date
Si la segunda dice UTC y la primera no, ese es el problema.
La solución: la variable TZ
Lo más portable es definir la variable de entorno TZ con el nombre de tu zona horaria, que para Colombia es America/Bogota.
Con docker run:
docker run -e TZ=America/Bogota mi-imagen
Con Docker Compose:
services:
app:
image: mi-imagen
environment:
- TZ=America/Bogota
Si no sabes el nombre exacto de tu zona, puedes listarlas:
timedatectl list-timezones | grep America
Después hay que recrear el contenedor; reiniciarlo no basta, porque las variables de entorno se fijan al crearlo:
docker compose up -d
Cuando la variable no tiene efecto
Si definiste TZ y el contenedor sigue en UTC, revisa lo siguiente.
La imagen no incluye los datos de zonas horarias
Las imágenes mínimas, como las basadas en Alpine, no traen el paquete tzdata. Sin él, el sistema no reconoce America/Bogota y se queda en UTC sin avisar. Agrégalo en tu Dockerfile:
FROM alpine:3.20
RUN apk add --no-cache tzdata
ENV TZ=America/Bogota
En imágenes basadas en Debian o Ubuntu el paquete se llama igual:
RUN apt-get update && apt-get install -y tzdata && rm -rf /var/lib/apt/lists/*
La variable está en un archivo que no se carga
Un archivo .env junto al docker-compose.yml no pasa sus variables al contenedor; Compose solo lo usa para sustituir valores dentro del propio archivo. Para que lleguen al contenedor hay que declararlo:
services:
app:
image: mi-imagen
env_file:
- .env
Para ver qué variables recibió el contenedor:
docker exec mi-contenedor env | grep TZ
La aplicación pide la hora en UTC
Algunos programas ignoran la zona del sistema porque el código pide UTC a propósito. En Python, datetime.utcnow() siempre devuelve UTC, mientras que datetime.now() respeta TZ. Si tu aplicación compara la hora actual con un horario configurado, revisa cuál de las dos usa.
Alternativa: compartir la configuración del anfitrión
También puedes montar los archivos de zona horaria de tu equipo en modo de solo lectura:
services:
app:
image: mi-imagen
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
Funciona en un solo equipo, pero ata el contenedor a esa máquina. Si piensas desplegarlo en otro servidor, la variable TZ es más predecible.
Cuidado con las tareas programadas
Si usas cron dentro de un contenedor, el servicio lee la zona horaria al arrancar. Después de corregirla, recrea el contenedor y prueba con una tarea de ensayo que se ejecute a la hora esperada.
En registros y bases de datos conviene guardar las fechas en UTC y convertirlas a hora local solo al mostrarlas; así no hay sorpresas si algún día mueves el servicio a un servidor en otra región.