265

Where do Docker containers get their time information? I've created some containers from the basic ubuntu:trusty image, and when I run it and request 'date', I get UTC time.

For awhile I got around this by doing the following in my Dockerfile:

RUN sudo echo "America/Los_Angeles" > /etc/timezone

However, for some reason that stopped working. Searching online I saw the below suggested:

docker run -v /etc/timezone:/etc/timezone [image-name]

Both these methods correctly set the timezone though!

$ cat /etc/timezone
America/Los_Angeles
$ date
Tue Apr 14 23:46:51 UTC 2015

Anyone know what gives?

Chockomonkey
  • 2,793

12 Answers12

373

The secret here is that dpkg-reconfigure tzdata simply creates /etc/localtime as a copy, hardlink or symlink (a symlink is preferred) to a file in /usr/share/zoneinfo. So it is possible to do this entirely from your Dockerfile. Consider:

ENV TZ=America/Los_Angeles
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

And as a bonus, TZ will be set correctly in the container as well.

This is also distribution-agnostic, so it works with pretty much any Linux.

Note: if you are using an alpine based image you have to install the tzdata first. (see this issue here)

Looks like this:

RUN apk add --no-cache tzdata
ENV TZ America/Los_Angeles
Michael Hampton
  • 252,907
119

Usually it is sufficient to set an environment variable in the docker container, like so:

docker run -e TZ=Europe/Amsterdam debian:jessie date

Of course this would work also with docker-compose.

Victor Klos
  • 1,321
41

You can add your local files (/etc/timezone and /etc/localtime) as volume in your docker-container.

Update your docker-compose.yml with the following lines.

volumes:
    - "/etc/timezone:/etc/timezone:ro"
    - "/etc/localtime:/etc/localtime:ro"

Now the container time is the same as on your host

Y4roc
  • 511
23

Mounting /etc/localtime in the image, so it is in sync with host -v is the most popular one.

But see issue 12084:

it is not correct because it does not work when the software requires instead the file /etc/timezone to be set.
That way you are using leaves it as the default value etc/UTC.

I have determined that actually there is no foolproof elegant way to set the time zone inside of a docker container.
So have finally settled on this solution:

App dockerfile:

# Relocate the timezone file
RUN mkdir -p /config/etc && mv /etc/timezone /config/etc/ && ln -s /config/etc/timezone /etc/

App entrypoint script:

# Set timezone as specified in /config/etc/timezone
dpkg-reconfigure -f noninteractive tzdata

Data volume /config dockerfile, localized to a specific country or region:

# Set the time zone
RUN echo "Europe/London" > /config/etc/timezone

... it is not elegant because involving 3 separate files, and re-creating /etc/localtime on every runtime container start. Which is rather wasteful.

However it does work properly, and successfully achieve separation between the base app image, and each per-country localized configuration.
In 3 lines of code.

VonC
  • 2,778
18

In ubuntu 16.04 image there is bug. Solution was

    ENV TZ 'Europe/Tallinn'
    RUN echo $TZ > /etc/timezone && \
    apt-get update && apt-get install -y tzdata && \
    rm /etc/localtime && \
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    dpkg-reconfigure -f noninteractive tzdata && \
    apt-get clean
qwerty
  • 281
6

if you are using docker image based on ubuntu :

# Change the docker default timezone from UTC to SGT
echo "Asia/Singapore" > /etc/timezone
dpkg-reconfigure tzdata
date
Xianlin
  • 685
5

Adding my two cents here, because I've tried several of these but none worked on alpine-based images.

However, this did the trick:

ENV TZ=America/Toronto
RUN apk update
RUN apk upgrade
RUN apk add ca-certificates && update-ca-certificates
RUN apk add --update tzdata
RUN rm -rf /var/cache/apk/*

[Source]

Alpha
  • 151
4

In alpine basic Image (example use node:10.16.0-alpine):

Dockerfile

FROM node:10.16.0-alpine

ENV TZ=America/Los_Angeles

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm i --production

COPY . .

CMD node index.js

flynn
  • 141
4

Using a Fedora container (likely to work with ubuntu also):

The simplest solution I found was to use the following in docker-compose.yml

environment: 
  TZ: "${TZ:-America/Los_Angeles}"

Then in your .env file (which docker-compose automatically reads)

TZ=America/Los_Angeles

This allows you to put docker-compose.yml under version control and use a customized .env file which can be ignored by git.

You get a default value for the container and you get customization, best of both worlds.

For Fedora no other changes were necessary, it just works!

3

Thanks to VonC for the information and link to the issue. This seems like such a convoluted mess, so I did some testing on my own idea of how to solve this and it seems to work great.

>docker run -it ubuntu:trusty /bin/bash
#dpkg-reconfigure tzdata

(follow prompts to select my timezone)

>docker commit [container-id] chocko/ubuntu:local

Then I updated my Dockerfiles to reflect this:

FROM chocko/ubuntu:local

There must be something wrong with this because it seems too easy to be overlooked... Or is this acceptable?

Chockomonkey
  • 2,793
3

A more generic way to set the timezone in docker run arguments:

-e TZ=`ls -la /etc/localtime | cut -d/ -f8-9`

Or for reuse:

function GET_TZ () {
    ls -la /etc/localtime | cut -d/ -f8-9
}

...
-e TZ=`GET_TZ`
Mugen
  • 151
1

The simplest way is to add -e option or ENV directive to set TZ environment variable, because debian, ubuntu, etc. already included tzdata.

Someone recommends to mount the timezone from the host:

$ docker run -it --rm \
-v /etc/localtime:/etc/localtime \
-v /etc/timezone:/etc/timezone \
debian:bullseye date
Mon Jul  3 19:41:30 CST 2023

This may work, but it is dangerous. Because /etc/localtime is actually a symbol link (in some newer distributions), and Docker by default follow the symbol link. As a result, the timezone data (instead of the symbol link it self) is overridden silently.

$ docker run -it --rm debian:bullseye \
sh -c 'ls -l /etc/localtime && tail -n1 /etc/localtime'
lrwxrwxrwx 1 root root 27 Mar 20 00:00 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
UTC0
$ docker run -it --rm -v /etc/localtime:/etc/localtime debian:bullseye \
sh -c 'ls -l /etc/localtime && tail -n1 /etc/localtime'
lrwxrwxrwx 1 root root 27 Mar 20 08:00 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
CST-8

That is why this does not work:

$ docker run -it --rm \
-v /usr/share/zoneinfo:/usr/share/zoneinfo \
-v /etc/localtime:/etc/localtime \
-v /etc/timezone:/etc/timezone \
debian:bullseye date
Mon Jul  3 11:41:59 UTC 2023