Timezone in JVM
Table of Contents
I wrote a Scala code to get the current time. However, the output is different on the development server and docker.
import java.util.Calendar
println(Calendar.getInstance().getTime)
On my development server, it outputs Sun Oct 18 18:01:01 CST 2020
, but in docker, it print a UTC time.
I guess it related to the timezone setting and do a research, here is the result.
How Did JVM Detect Timezone #
All of the code can be found in this function: private static synchronized TimeZone setDefaultZone()
String zoneID = AccessController.doPrivileged(new GetPropertyAction("user.timezone"));
// if the time zone ID is not set (yet), perform the
// platform to Java time zone ID mapping.
if (zoneID == null || zoneID.isEmpty()) {
String javaHome = AccessController.doPrivileged(
new GetPropertyAction("java.home"));
try {
zoneID = getSystemTimeZoneID(javaHome);
if (zoneID == null) {
zoneID = GMT_ID;
}
} catch (NullPointerException e) {
zoneID = GMT_ID;
}
}
First, it will check whether JVM has user.timezone
property. If not, it will call this native method getSystemTimeZoneID
, it was implemented in java.base/share/native/libjava/TimeZone.c, and the main logic is in java.base/unix/native/libjava/TimeZone_md.c.
In Timezone_md.c
, it will find timezone by following steps, it will return the timezone immediately once found.
- Find
TZ
environment. - Read
/etc/timezone
. - Read
/etc/localtime
. If it is a soft link(ex:/usr/share/zoneinfo/Asia/Shanghai
), return timezone by path. Otherwise, compare the content with all files in/usr/share/zoneinfo
, if found, return timezone. - Return
GMT
as timezone.
How to Change Timezone #
The available timezone in Linux can be listed by this command: timedatectl list-timezones
Add JVM param #
You can add -Duser.timezone=Asia/Shanghai
as JVM parameters.
Set TZ environment variable #
Add export TZ=Asia/Shanghai
in .bashrc
.
Change /etc/timezone
#
Set its content to Asia/Shanghai
Change /etc/localtime
#
Link it to /usr/share/zoneinfo/Asia/Shanghai
Change timezone manually in Java Program #
All of these methods should work
- Add this line before get time:
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))
- Set JVM property by code
System.setProperty("user.timezone", "Asia/Shanghai")
- Set timezone manually in Calendar
Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai"))