Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenJDK 1.8.0 in Docker container has different timezone than /etc/timezone and from the host

I have a Linux box running a Docker container, which is running TomEE, and running a WAR I built.

On the base Linux box, I get a "date" value of "Fri Jan 20 10:37:27 PST 2017". The TZ environment variable is not set.

When I run the following class:

import java.util.Date;
import java.util.TimeZone;

public class DatePrint {
        public static void main(String[] args) {
                System.out.println("date[" + new Date() + "] tzoffset[" + TimeZone.getDefault().getOffset(new java.util.Date().getTime()) + "]");
        }
}

I get this:

date[Fri Jan 20 10:39:02 PST 2017] tzoffset[-28800000]

This is all fine.

In my Docker container running on the box, where I have "-v /etc/localtime:/etc/localtime" as one of the volume mappings, I obviously have the same /etc/localtime file. The TZ environment variable is not set. When I run "date" inside the container, I get a time value in the same timezone (PST) as in the base host.

I then compile and run the same Java class as above, and I get the following:

date[Fri Jan 20 18:30:38 UTC 2017] tzoffset[0]

I then manually set the TZ environment variable in the container (remember that it's not set in the base host) to "America/Los_Angeles" (I verified this value by looking at the file that "/etc/localtime" symlinks to on the base host).

I then reran the class on the container and got this:

date[Fri Jan 20 10:35:08 PST 2017] tzoffset[-28800000]

Note that the two versions of Java on the base host and the container are almost identical. They are both OpenJDK 1.8.0_111 (b15 on the host, b14 on the container).

So, can someone explain what's going on here? On the base host, I had "etc/localtime" pointing to the proper file, but I did not have TZ set. It reports the correct timezone with "date" and in the Java class. On the container, "/etc/localtime" is pointing to the proper file, and I didn't originally have TZ set. The "date" command returns the correct value, but Java did not.

I had to manually set TZ on the container to the TZ value from the host, and that made it work. I'd really rather not do this. That seems like a hack to me.

Update:

I noticed the following in the "localtime(5)" man page:

Because the timezone identifier is extracted from the symlink target name of /etc/localtime, this file may not be a normal file or hardlink.

So, that may be part of my problem. It's still curious that "date" from the shell works fine, but Java (without the TZ setting) gets confused.

like image 272
David M. Karr Avatar asked Oct 23 '25 02:10

David M. Karr


2 Answers

i had the same issue as you (CentOS, Docker, OpenJDK). We solved it this way:

Don't mount localtime, mount /etc/timezone.

If you don't have a /etc/timezone file (e.g. on CentOS), you can do something like this (on the host):

timedatectl | awk '/Time zone:/ {print $3}' > /etc/timezone_host

Then in the container (e.g. entry point)

TZ_HOST=$(cat /etc/timezone_host)
echo $TZ_HOST > /etc/timezone
export TZ=$TZ_HOST
dpkg-reconfigure --frontend noninteractive tzdata
like image 175
floushee Avatar answered Oct 24 '25 17:10

floushee


Follow Gilles's answer in https://unix.stackexchange.com/questions/452559/what-is-etc-timezone-used-for, Java reads /etc/timezone instead of /etc/localtime because of historical reasons. Further explanations can be found in that post.

like image 41
CoconutMooncake Avatar answered Oct 24 '25 15:10

CoconutMooncake