JDK-8200722 : Java does not support the :characters format of the TZ environment variable
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.time
  • Affected Version: 9.0.4,10,11
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: x86_64
  • Submitted: 2018-03-29
  • Updated: 2019-05-16
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Description
FULL PRODUCT VERSION :
java 9.0.4
Java(TM) SE Runtime Environment (build 9.0.4+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Red Hat Enterprise Linux Server release 7.4 (Maipo)
Linux alexrhel7test.mpr.org 3.10.0-693.21.1.el7.x86_64 #1 SMP Fri Feb 23 18:54:16 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

EXTRA RELEVANT SYSTEM CONFIGURATION :
Brand new VM, nothing unique as far as the configuration.
Installed using Redhat 7.4 minimal

A DESCRIPTION OF THE PROBLEM :
It seems that java doesn't support a format of the TZ environment variable in Linux. On http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html at the bottom the of document, the format :characters is defined. 

Java doesn't seem properly read the variable if TZ is set to a file path. When the TZ variable is set to :/etc/localtime, the java timezone doesn't properly honor daylight savings time and all time operations are an hour off.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I installed a fresh RHEL7.4 minimal system, updated it with yum update and rebooted.
During installation I set the timezone to American/Chicago
Then I downloaded jdk-9.0.4_linux-x64_bin.rpm from Oracle's website 
Then I ran "yum install jdk-9.0.4_linux-x64_bin.rpm"

I used this sample java code in a file called GetDate.java:
import java.util.Date;

class GetDate {
  /** Print a hello message */
  public static void main(String[] args) {
    Date today = new Date();
    System.out.println(today);
  }
}

Then I ran "javac GetDate.java"
Then I ran "java GetDate"

The output was
$ java GetDate
Wed Mar 21 14:48:35 CDT 2018

If I create a timezone environment variable:
export TZ=:/etc/localtime

Then run the java command again, I get different result, one hour off:
$ java GetDate
Wed Mar 21 13:50:04 GMT-06:00 2018

If I run the local date command, I get the correct time, even with the environment variable
$ date
Wed Mar 21 14:50:06 CDT 2018


$ ls -hla /etc/localtime
lrwxrwxrwx. 1 root root 37 Mar 21 13:28 /etc/localtime -> ../usr/share/zoneinfo/America/Chicago

If I unset the TZ environment variable, it works
$ unset TZ
$ java GetDate
Wed Mar 21 14:52:38 CDT 2018

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect the test script to show the correct time with the correct hour based on daylight savings.
ACTUAL -
Instead I see time that is an hour off.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.Date;

class GetDate {
  /** Print a hello message */
  public static void main(String[] args) {
    Date today = new Date();
    System.out.println(today);
  }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Unsetting the TZ variable works.
Setting the TZ variable to "American/Chicago" works.


Comments
Since it is described as OS specific behavior, it would need close consideration. And a CSR would be required since it changes behavior. And would need to be specified for each OS. Before making a patch, propose and discuss the change.
19-12-2018

Looking over the code, I see the issue is that any value of TZ is assumed to be a zonename. So, America/New_York works, but if it's a file path, the path is sent back to the calling Java code unaltered, which can't match it to a zone and instead falls back to GMT. I believe different behaviour should be used if the TZ value starts with a '/' (or ':/', but it already just drops the ':') 1. If the path is /etc/localtime, use the existing logic to find out which zone that points to. 2. If it's a timezone path, use getZoneName to strip the beginning and return the zone name The logic for both these options is already there for the case where TZ is unset. It's just ignored where TZ is set, preferring to just use that value as is. A patch for this should be fairly trivial.
19-12-2018

To reproduce the issue, follow the steps described in bug report: JDK 11-ea +7 - Fail p@pi-VirtualBox:/shared$ jdk-11/bin/java GetDate Wed Apr 04 05:07:33 CDT 2018 p@p:/shared$ export TZ=/etc/localtime p@p-VirtualBox:/shared$ jdk-11/bin/java GetDateWed Apr 04 04:09:38 GMT-06:00 2018 p@p-VirtualBox:/shared$ unset TZ p@p-VirtualBox:/shared$ jdk-11/bin/java GetDate Wed Apr 04 05:10:16 CDT 2018
04-04-2018