Timezones are a common source of confusion when containerizing an application. Will your cron tasks run at the right time? Docker containers don’t inherit the host’s timezone, so you can run into unexpected scheduling issues that wreak havoc with your application.
date command running natively on an Ubuntu 20.04 host in the British Summer Time timezone:
And here’s the same command in a container based on an unmodified
The container is using the UTC timezone, creating a one hour difference between the two times.
How Do Linux Timezones Work?
Most Linux distributions use the
tzdata package to provide timezone information. When
tzdata is installed, you can inspect the current timezone by reading the
You’ll also have an
/etc/localtime file. This is a symlink to the correct timezone database for the selected location:
If you change the timezone, using
dpkg-reconfigure tzdata, the
/etc/localtime symlink gets updated to point to the new database. The output of commands like
date will be adjusted to include the active timezone’s offset.
The Problem With Containers
The challenge with containers derives from setting the timezone in the first place. If you think back to when you setup your host, you’d have needed to set the timezone as part of the operating system installation. When you run a new container, it starts immediately though, without any “installation” stage. There’s no opportunity to select an appropriate timezone.
Theoretically, container runtimes could offer automatic inheritance of the host’s timezone. This doesn’t happen as it might lead to unexpected results when deploying to remote environments. It would be easy to overlook that your cron schedule works on your local machine but executes unexpectedly in a managed Kubernetes cluster using UTC time.
Container images ship with a baked-in timezone instead. For most popular images, this will be UTC. Many base images, particularly minimal ones, won’t even include the
tzdata package. You’ll have no
Adding Timezones to Your Containers
The first part of setting the proper timezone is to make sure
tzdata is installed. If your image doesn’t include it, you’ll need to manually add the package as part of your
FROM ubuntu:latest ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y tzdata
tzdata installs, you usually get an interactive prompt that lets you select the correct timezone from a menu. This is unhelpful when you’re programmatically building Docker containers. Setting the
DEBIAN_FRONTEND environment variable suppresses the prompt and defaults the timezone to UTC.
Once you’ve got
tzdata into your image, you’re ready to configure the correct timezone for your application. The simplest approach is to set the
TZ environment variable to the timezone you want to use:
FROM ubuntu:latest ENV TZ=Europe/London ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y tzdata
If you prefer, you can set the
TZ variable when you start containers. Pass it as an environment variable to
docker run. This lets you override an image’s default timezone, provided it includes the
docker run -e TZ=Europe/London -it ubuntu:latest
An alternative to environment variables is the
/etc/timezone file. You can write the required timezone as part of your
Dockerfile. If you use this method, you must reconfigure
tzdata using your package manager. Remember to use non-interactive mode or you’ll receive the graphical timezone prompt again.
FROM ubuntu:latest RUN echo "Europe/London" > /etc/timezone RUN dpkg-reconfigure -f noninteractive tzdata
If you want to guarantee timezone synchronization with the host, you can mount your local
tzdata files into your containers. You’ll still need
tzdata inside the container for this to work correctly.
docker run -v /etc/timezone:/etc/timezone -v /etc/localtime:/etc/localtime -it ubuntu:latest
Although Docker doesn’t provide any built-in support for timezones, that’s not true of all container engines. Podman has a dedicated
--tz flag which lets you set the timezone when creating a new container:
podman run --tz=Europe/London -it ubuntu:latest
Behind the scenes, Podman will mount an appropriate
/etc/localtime file for you. The specified timezone will persist for the lifetime of the container.
Podman also lets you set a default timezone for containers created without the
--tz flag. Create or edit
.config/containers/containers.conf in your home directory. Add a
tz setting on a new line in the file:
# Used when no --tz flag is given tz = "Europe/London"
Podman’s native timezone integration makes it easier to work with than Docker. As Podman’s CLI is compatible with Docker’s, making the switch can be worth considering if you’re frequently working with containers in different timezones.
Timezones are often overlooked when setting up Docker containers. Most base images default to UTC time which can lead to confusion when the host’s timezone is different.
By installing the
tzdata package, your container gains compatibility with all timezones via the
TZ environment variable,
/etc/localtime. Alternatively, you can sync your host’s timezone by mounting the relevant files into your containers.
Finally, remember that these considerations also apply to hosted Docker services and Kubernetes clusters. Your containers will use UTC time unless instructed otherwise. As long as you can set environment variables, you’ll be able to use
TZ to adjust the timezone for your workloads.