Skip to content
Advertisement

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:

JavaScript

Ubuntu 18.04.2 LTS (bionic)

JavaScript

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

JavaScript

Raspbian 9.9 (stretch)

JavaScript

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)

JavaScript

Advertisement

Answer

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:

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.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement