Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the JRE support posix TZ description rather than TZ name?

Java doesn't appear to apply DST offset when the OS uses a POSIX time zone description rather than a time zone name. Is the use of a TZ description unsupported by the JRE or is this behavior a bug?

More details...

I'm working on a Linux (Debian) based system where the TZ environment variable is set to a POSIX formatted TZ like STD+7DST+6,M3.2.0/02:00:00,M11.1.0/02:00:00 instead of a TZ name such as America/Denver. (See TZ Variable)

While this seems to work correctly for date and related system tools, when I try to find the time in a java application, it doesn't appear it has been correctly adjust for DST. This results in the time being wrong for part of the year when DST is in effect.

I've tested this on a several different systems and seen the same results on each (test w/ results are below)

This behavior actually surfaced in an application that uses Quartz Scheduler but I've since been able to reproduce the issue with the following SSCCE:

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

public class CheckTime {
    public static void main(String[] args) {
        TimeZone tz = TimeZone.getDefault();
        Date now = new Date();
        System.out.println("Current time " + now.toString());
        System.out.println("Current time zone " + tz.getDisplayName());
        System.out.println("Current time zone in DST? " + tz.inDaylightTime(now));
    }
}

Ubuntu 18.04.2 LTS (bionic)

$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-1ubuntu1~18.04.1-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)

$ export TZ="STD+7DST+6,M3.2.0/02:00:00,M11.1.0/02:00:00"
$ date
Fri Aug  9 07:02:27 DST 2019
$ java CheckTime
Current time Fri Aug 09 06:02:30 GMT-07:00 2019
Current timezone GMT-07:00
Current timezone in DST? false

$ export TZ="America/Denver"
$ date
Fri Aug  9 07:03:29 MDT 2019
$ java CheckTime
Current time Fri Aug 09 07:03:32 MDT 2019
Current timezone Mountain Standard Time
Current timezone in DST? true

Custom ARM32hf build, based on debian (kernel 4.1.0-altera)

$ java -version
openjdk version "1.8.0_162"
OpenJDK Runtime Environment (Zulu Embedded 8.27.0.91-linux-aarch32hf) (build 1.8.0_162-b91)

$ export TZ="STD+7DST+6,M3.2.0/02:00:00,M11.1.0/02:00:00"
$ date
Fri Aug  9 07:06:59 DST 2019
$ java CheckTime
Current time Fri Aug 09 06:07:03 GMT-07:00 2019
Current time zone GMT-07:00
Current time zone in DST? false

$ export TZ="America/Denver"
$ date
Fri Aug  9 07:09:45 MDT 2019
$ java CheckTime
Current time Fri Aug 09 07:09:49 MDT 2019
Current time zone Mountain Standard Time
Current time zone in DST? true

Raspbian 9.9 (stretch)

$ java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) Client VM (build 25.65-b01, mixed mode)

$ export TZ="STD+7DST+6,M3.2.0/02:00:00,M11.1.0/02:00:00"
$ date
Fri Aug  9 07:12:52 DST 2019
$ java CheckTime
Current time Fri Aug 09 06:12:57 GMT-07:00 2019
Current time zone GMT-07:00
Current time zone in DST? false

$ export TZ="America/Denver"
$ date
Fri Aug  9 07:13:42 MDT 2019
$ java CheckTime
Current time Fri Aug 09 07:13:44 MDT 2019
Current time zone Mountain Standard Time
Current time zone in DST? true

EDIT

Curiously, I see slightly different results on a mac. Java still doesn't report that the system is in DST, but it at least reports the correct local time.

MacOS 10.14.6 (Mojave)

$ java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment Corretto-8.212.04.2 (build 1.8.0_212-b04)
OpenJDK 64-Bit Server VM Corretto-8.212.04.2 (build 25.212-b04, mixed mode)

$ export TZ="STD+7DST+6,M3.2.0/02:00:00,M11.1.0/02:00:00"
$ date
Fri Aug  9 09:47:14 DST 2019
$ java CheckTime
Current time Fri Aug 09 09:47:18 GMT-06:00 2019
Current timezone GMT-06:00
Current timezone in DST? false

$ export TZ="America/Denver"
$ date
Fri Aug  9 09:49:04 MDT 2019
$ java CheckTime
Current time Fri Aug 09 09:49:08 MDT 2019
Current timezone Mountain Standard Time
Current timezone in DST? true

$java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

$ export TZ="STD+7DST+6,M3.2.0/02:00:00,M11.1.0/02:00:00"
$ date
Fri Aug  9 10:19:23 DST 2019
$java CheckTime
Current time Fri Aug 09 10:19:40 GMT-06:00 2019
Current timezone GMT-06:00
Current timezone in DST? false

$ export TZ="America/Denver"
$ date
Fri Aug  9 10:21:03 MDT 2019
$ java CheckTime
Current time Fri Aug 09 10:21:07 MDT 2019
Current timezone Mountain Standard Time
Current timezone in DST? true

like image 364
Jason Braucht Avatar asked Aug 09 '19 13:08

Jason Braucht


People also ask

What is Posix TZ format?

The TZ variable specified in POSIX format contains all the information required to identify the time zone, specify when to switch DST on and off, and specify the offset from Coordinated Universal Time (UTC).

How do I set Central time zone in Java?

If want to the code to provide the current time considering the daylight saving adjustment from CST to CDT or vice versa ,you can use the "CST6CDT" timezone. in place of "CST" in SimpleDateFormat.

How does Java determine TimeZone?

Typically, you get a TimeZone using getDefault which creates a TimeZone based on the time zone where the program is running. For example, for a program running in Japan, getDefault creates a TimeZone object based on Japanese Standard Time.

How do I get JVM TimeZone?

By default, the JVM reads time zone information from the operating system and stores it in the TimeZone class. To get the default time zone set in the JVM using the method TimeZone. getDefault() . To get the list of all supported timezones, use the method TimeZone.


1 Answers

It is not a bug. It is a feature.

According to the javadoc for ZoneId, that POSIX syntax for specifying zones is not supported:

Time-zone IDs

The ID is unique within the system. There are three types of ID.

The simplest type of ID is that from ZoneOffset. This consists of 'Z' and IDs starting with '+' or '-'.

The next type of ID are offset-style IDs with some form of prefix, such as 'GMT+2' or 'UTC+01:00'. The recognised prefixes are 'UTC', 'GMT' and 'UT'. The offset is the suffix and will be normalized during creation. These IDs can be normalized to a ZoneOffset using normalized().

The third type of ID are region-based IDs. A region-based ID must be of two or more characters, and not start with 'UTC', 'GMT', 'UT' '+' or '-'. Region-based IDs are defined by configuration, see ZoneRulesProvider. The configuration focuses on providing the lookup from the ID to the underlying ZoneRules.

Time-zone rules are defined by governments and change frequently. There are a number of organizations, known here as groups, that monitor time-zone changes and collate them. The default group is the IANA Time Zone Database (TZDB). Other organizations include IATA (the airline industry body) and Microsoft.

Each group defines its own format for the region ID it provides. The TZDB group defines IDs such as 'Europe/London' or 'America/New_York'. TZDB IDs take precedence over other groups.

See also:

  • TZ Var to Java TimeZone?

If you wrote some code to parse that syntax, you should be able to use the data to construct a SimpleTimeZone (javadoc). Unfortunately, this forces you to continue using the old ("mostly deprecated") Date class and friends.

The new (in Java 8) java.time.* classes don't appear to have an easy way to construct your own ZoneId from a set of rules. (Maybe it could be done by implementing your own ZoneRuleProvider (javadoc), but it looks complicated.)

So (IMO) you would be better off getting your OS to use the standard TZDB zone ids.


You commented:

On this particular system, neither "/etc/localtime" nor "/etc/timezone" exist.

If you are running Ubuntu Bionic, "/etc/localtime" should exist. It should be a symlink to a binary timezone file in the "/usr/share/zoneinfo" tree. See https://linuxize.com/post/how-to-set-or-change-timezone-on-ubuntu-18-04/. Or perhaps the problem is that the system has been deliberately configured to not know its local timezone.

like image 63
Stephen C Avatar answered Sep 29 '22 23:09

Stephen C