Debugging inconsistent timezone between Java & Linux
Debugging inconsistent timezone between Java & Linux
Have you ever noticed that in some cases, Java will not take the time zone which is configured in a server? This has serious impacts if the server handles scheduling tasks and runs them periodically.
Before diving deep down, let’s understand what is a time zone?
Time Zones are geographical world globe division of 15 degree each, starting at Greenwich, England. It’s a uniform standard time for legal, commercial and social purposes.
The Issue
Timezone difference between the system and java
While executing the below code, It will print the system time along with the timezone. I’ve added the output of the date command as well. Java code to print the current date using new Date()


Even though the system timezone is configured as PST, java prints the timezone as GMT.
Quick fix
- Set
user.timezoneinthe command line as-Duser.timezone=America/Los_Angeles - Set the environmental variable
TZto provide the timezone.
The above solutions will work, but to understand and fix it once for all, read further for the actual fix. (All required source code links are embedded in the method names)
Detailed Explanation: The Why?
Backtracking toString() method of Date class
In the example java code, we call System.out.println of new Date(). We know that java calls an object’s .toString() method internally to provide the string representation of an object. Let’s take a look at the toString method of the Date class in java.

The timezone on Line:16is set by calling the date.getZone(). The variable date is initialized by calling the normalize() method.

The timezone in normalize is set by calling the TimeZone.getDefaultRef() in TimeZone.java which then calls setDefaultZone() to get the system timezone.


Now, let's break up and understand what the setDefaultZone() does.
- It checks for the zone by checking the
user.timezoneproperty (which we didn’t set via the command line). - If the
user.timezoneproperty isnull, it gets thejava.homeproperty and calls thegetSystemTimeZoneID()which is a native method. - Any
NULLvalues will set the timezone to default GMT. (So, this is why the timezone is set to GMT!)

Ignoring the unwanted details, let’s focus on what the findJavaTZ_md() does.

Now, we can understand why the quick search solutions mentioned to set values for user.timezone and TZ! In our case, we didn’t set the TZ environmental variable which means TZ = NULL.
It calls getPlatformTimeZoneID() if TZ is NULL. (We’re about to reach a conclusion in the next step! Hang on..)

As the comment says, it will check for /etc/timezone file which contains the system timezone information. I checked in my Ubuntu machine for the file and it's straightforward.

If the file is not present, it checks /etc/localtime to obtain the timezone.

Here’s what happens in the above code.
- Get the file status of
/etc/localtimeusing lstat - Check whether it's a symlink and read the symlink to obtain the timezone.
For lstat to work as expected, it's required to have the executable x permission on the file (as stated in the manpage of lstat). In my case, the /etc/localtime file doesn’t have the executable permission set. Hence, it returns NULL taking the default timezone of GMT.

Obtaining Timezone via symlink
If the file has the required permission set, the output will be like the below one. After resolving the symlink, the zone info will be taken using the getZoneName method.


If the /etc/localtimefile is not a symlink, the getPlatformTimeZoneID method will try to open and read the file like /etc/timezone. As the last fallback, it will recursively iterate the /usr/share/zoneinfodirectory to find the timezone. When none of them works out, the timezone is set to GMT - the default!
Actual Fix
I just had to create a symlink of /etc/localtime from /usr/share/zoneinfo/America/Los_Angeles.

After setting the symlink, running the DateExample program yields the expected result.
Final Output

Thank you for reading! See you in the next post.