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?

3
  • 5
    If you use Alpine, you need to install tzdata first, see here github.com/gliderlabs/docker-alpine/issues/136 Commented Dec 27, 2017 at 14:56
  • 2
    FYI . . . I wish to set the timezone of container at docker run time not at docker build/dockerfile time. Using -v /etc/localtime:/etc/localtime:ro (CentOS) sort of works. Inside container command-line date returns date in the expected timezone format. BUT jenkins running in container thinks timezone is UTC. Why? /etc/localtime is a symlink to ../usr/share/zoneinfo/UTC in built container. The content of the UTC file in container is now the new timezone. But jenkins (and perhaps other java based software) use the name of the symlink which is still "UTC". Searching for solution . . . Commented Jan 21, 2019 at 17:29
  • 1
    Need 2 things, 1. when container is created use an init script to set /etc/localtime symlink and /etc/timezone and 2. for jenkins timezone is taken from two java options, these options need to be passed to the init script which starts the jenkins process. e.g. " -Dorg.apache.commons.jelly.tags.fmt.timeZone=America/New_York -Duser.timezone=America/New_York ". Apologies, this is jenkins specific but hopefully useful for some other jenkins users. Commented Jan 22, 2019 at 16:59

12 Answers 12

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 
14
  • 43
    List of TZ names: en.wikipedia.org/wiki/List_of_tz_database_time_zones Commented Aug 14, 2017 at 9:19
  • 12
    With Ubuntu:16.04 (and maybe others version) you need to have tzdata package installed for make this work. Commented Oct 23, 2017 at 1:29
  • 14
    Am I the only one who thinks it is not very smart to hardcode a timezone in the Dockerfile? Commented Nov 2, 2018 at 15:39
  • 2
    @Wolfgang This is an example. You can provide it in any other way you would ordinarily provide environment variables, such as the command line, docker-compose.yml, etc. Commented Nov 2, 2018 at 15:42
  • 4
    I noticed that, at least for Alpine-based images, just setting the TZ variable was enough. I didn't have to setup the symlinks or anything else. Commented Jun 21, 2019 at 21:54
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.

4
  • 9
    This seems to be the most elegant way. Take care that some base image, like ubuntu:16.04, does not have the tzdata package which should be added in Dockerfile. Commented May 19, 2017 at 10:25
  • 2
    +1 -- I agree with Julien; this appears to be the most elegant approach for setting time zones at runtime. This works well with CentOS. Alpine image does require installation of 'tzdata' package, which is preferred over harcoding configurations at build time unless the extra 3MB image payload cannot be tolerated :) Commented Dec 27, 2017 at 16:09
  • This seems good but seems to not work for me (with CentOS 7.5.1804 and tzdata-2018e-3.el7.noarch) ? sad face Commented Jan 21, 2019 at 17:19
  • 2
    WARNING: I've end up with programs partially using UTC and partially TZ info. It took me a while to figure out why my sql client is using UTC while $ date gives me correct time zone. :( Commented Apr 7, 2022 at 14:36
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

8
  • 1
    If your on CentOS distrib host enter the command echo "Europe/Paris" > /etc/timezone before restarting the container. Commented Sep 18, 2017 at 13:21
  • 1
    Does this work on MacOS host? Commented Oct 26, 2017 at 23:24
  • 3
    Does not WORK in MAC Commented Jan 19, 2018 at 3:08
  • 7
    This will corrupt your zoneinfo db as /etc/localtime is a symlink (thus /usr/share/zoneinfo/Some/Thing is likely to get mounted as /usr/share/zoneinfo/UTC inside the container). Not to mention that you'd mix the db file from the host with the one in the container. Commented May 10, 2018 at 15:03
  • 6
    WARNING: This can cause strange bugs! See github.com/nodejs/node/issues/28743. At the very least you should mount /usr/share/zoneinfo as well. Commented Jul 8, 2020 at 10:24
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.

2
  • 2
    For me, it was : RUN echo "Europe/London" > /etc/timezone Commented Oct 19, 2017 at 11:54
  • @jpmottin So a bit as in serverfault.com/a/856593/783 then? Commented Oct 19, 2017 at 12:01
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 
2
  • 2
    Seriously...this is the only solution that worked! Commented Jun 30, 2017 at 22:13
  • 1
    Also had to do this - seems tzdata is no longer in some distros by default. Commented Jan 24, 2018 at 7:06
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 
1
  • This do not work. Try: docker run -it --rm ubuntu:latest bash -c 'apt update && DEBIAN_FRONTEND=noninteractive apt install -y tzdata && echo "Asia/Singapore" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata && date' Commented Jul 3, 2023 at 11:55
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]

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 
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?

2
  • This is also what I tried, but the timezone still resets itself after I exit the container. This is on Debian. Commented Jun 9, 2017 at 4:57
  • @MikeChamberlain did you happen to try the accepted answer by Michael Hampton above? I haven't implemented it myself, but I reckon it's the way to go considering the upvotes that it has received. Commented Jun 9, 2017 at 17:00
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` 
1
  • 1
    doesn't help if your base image is alpine(5MB) which doesn't has the "tzdata" installed Commented Jun 21, 2019 at 14:05
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 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.