Quick Links

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.

Here's the

        date
    

command running natively on an Ubuntu 20.04 host in the British Summer Time timezone:

Screenshot of the Date command on a Linux host

And here's the same command in a container based on an unmodified

        ubuntu:20.04
    

image:

Screenshot of the Date command in a Docker container

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 /etc/timezone file:

Screenshot of the /etc/timezone file contents on a Linux host

You'll also have an /etc/localtime file. This is a symlink to the correct timezone database for the selected location:

Screenshot of the /etc/localtime symlink on a Linux host

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 /etc/timezone or /etc/localtime files.

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 Dockerfile.

FROM ubuntu:latest
    

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y tzdata

When 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 tzdata package.

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

Other Techniques

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.

Summary

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/timezone, and /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.