Timezone in JVM
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
TZenvironment. - 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
GMTas 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"))