243

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,573
  • 2
  • 10
  • 10
  • 5
    If you use `Alpine`, you need to install `tzdata` first, see here https://github.com/gliderlabs/docker-alpine/issues/136 – Belter Dec 27 '17 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 . . . – gaoithe Jan 21 '19 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. – gaoithe Jan 22 '19 at 16:59

11 Answers11

350

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
Robin Thoni
  • 183
  • 1
  • 6
Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
  • 40
    List of TZ names: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones – BillyTom Aug 14 '17 at 09:19
  • 12
    With Ubuntu:16.04 (and maybe others version) you need to have `tzdata` package installed for make this work. – Opsse Oct 23 '17 at 01:29
  • 12
    Am I the only one who thinks it is not very smart to hardcode a timezone in the Dockerfile? – Wolfgang Nov 02 '18 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. – Michael Hampton Nov 02 '18 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. – code_dredd Jun 21 '19 at 21:54
  • I would have sworn that this used to work if I used `apk del tzdata` after setting it on Alpine, but it doesn't seem to work anymore. – mbomb007 Apr 14 '20 at 18:42
  • @mbomb007 If you want to delete `tzdata` package, then you need to _copy_ the file to `/etc/localtime` instead of symlinking it. – Michael Hampton Apr 14 '20 at 18:46
  • @MichaelHampton The Alpine code doesn't use a symlink. See the lower portion of the answer. – mbomb007 Apr 14 '20 at 18:47
  • @mbomb007 Eh? You did read the rest of the answer, right? – Michael Hampton Apr 14 '20 at 18:49
  • @MichaelHampton If I run `RUN apk add --no-cache tzdata\n ENV TZ America/Chicago\n RUN cp /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && apk del tzdata`, it doesn't work. And look at the guide for Alpine; no symlink is necessary, only the TZ env variable and the tzdata package. – mbomb007 Apr 14 '20 at 18:51
  • @mbomb007 Well that's strange. I suggest Alpine is doing something odd, and you probably should ask a new question. – Michael Hampton Apr 14 '20 at 18:52
  • @MichaelHampton [New question here](https://serverfault.com/q/1012310/352016) – mbomb007 Apr 14 '20 at 19:00
  • Alpine users might be able to get away without installing tzdata, and just setting the TZ environment variable, if one of the old deprecated abbreviations exists for their time zone. For example, TZ=EST5EDT for United States Eastern time. (Caveat: I have not verified which apps/libraries recognize these abbreviations, nor whether they obey modern daylight saving time schedules.) – ʇsәɹoɈ Sep 28 '20 at 00:05
  • Thank you very much! It's so easy when the explanation has already been received! – S.H. Oct 20 '21 at 16:04
115

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,281
  • 1
  • 8
  • 6
  • 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. – Julien Fastré May 19 '17 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 :) – Frelling Dec 27 '17 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 – gaoithe Jan 21 '19 at 17:19
  • 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. :( – Piotr Czapla Apr 07 '22 at 14:36
37

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
  • 471
  • 4
  • 4
  • 1
    If your on CentOS distrib host enter the command `echo "Europe/Paris" > /etc/timezone` before restarting the container. – CrazyMax Sep 18 '17 at 13:21
  • Does this work on MacOS host? – Redsandro Oct 26 '17 at 23:24
  • 2
    Does not WORK in MAC – Marcello de Sales Jan 19 '18 at 03:08
  • This used to work on MacOS but I just tried it again after a long time and I get the following. Not sure if High Sierra or a docker change caused this: "docker: Error response from daemon: Mounts denied: The path /etc/localtime is not shared from OS X and is not known to Docker. You can configure shared paths from Docker -> Preferences... -> File Sharing. See https://docs.docker.com/docker-for-mac/osxfs/#namespaces for more info." – gae123 Mar 04 '18 at 02:22
  • 5
    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. – ionelmc May 10 '18 at 15:03
  • Works on both Alpine and Debian images (from Linux host, of course). @ionelmc How will this corrupt anything if it's mounted read-only? – admirabilis May 30 '18 at 07:58
  • @TeresaeJunior inside the container you will have a broken zoneinfo db because the mount is wrong. Corrupion is not necessarily mixing up some bytes inside a file, it can be mixing up whole files as well ;) – ionelmc Jul 20 '18 at 10:18
  • 2
    WARNING: This can cause strange bugs! See https://github.com/nodejs/node/issues/28743. At the very least you should mount `/usr/share/zoneinfo` as well. – SystemParadox Jul 08 '20 at 10:24
22

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,653
  • 5
  • 29
  • 48
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
  • 2
  • 2
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
  • 1
  • 4
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
  • 41
  • 1
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!

4

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
  • 635
  • 4
  • 14
  • 21
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,573
  • 2
  • 10
  • 10
  • This is also what I tried, but the timezone *still* resets itself after I `exit` the container. This is on Debian. – Mike Chamberlain Jun 09 '17 at 04: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. – Chockomonkey Jun 09 '17 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`
Mugen
  • 151
  • 4