Java and incorrect timezone on Windows XP

How reliable is Java date, time and timezone API? In this article I discuss a relevant issue that may compromise application correctness when relying not only on date/time calculations, but also on reporting date/time according to local timezone and locale.

Recently I was debugging an activity scheduling application that was reporting events to weird time. Even worse, the weird time varied according to the desktop PC the application was running on. First, we assured that all date/time calculations were done correctly. Then, we double checked if Java reads the correct date/time from the system. Also, date, time and timezone configurations were set properly on the underlying platform. The odd behavior appeared on Java Virtual Machines from Sun, both JRE 1.5 and JRE. What was happening? We compared Java API results to Joda Time API.

The first investigation:

Real local time: 00:04

Real timezone: South America/Brasilia

Java API:

  • Default TimeZone: America/Rio_Branco
  • DST Savings: 0
  • Raw Offset(): -14400000
  • in Daylight Time: false
  • Supposed local time: 23:04

Joda Time API:

  • Default TimeZone: America/Rio_Branco
  • Standard Offset: -14400000
  • Offset: -14400000
  • Supposed local time: 23:04

Result:

Clearly, Java believes that the default timezone is America/Rio Branco (GMT-4:00), that is one hour behind South America/Brasilia (GMT-3:00). Even worse, both APIs incur the same error!

After opening the date/time dialog from the Windows XP Control Panel, and applying one of following changes, Java API starts working correcty:

  • Changing date/time manually and then changing back to original correct time.
  • Changing timezone and then back to original one.
  • Requesting automatic time update from time server.

Real local time: 00:17

Real timezone: South America/Brasilia

Java API:

  • Default TimeZone: America/Sao_Paulo
  • DST Savings: 3600000
  • Raw Offset(): -10800000
  • in Daylight Time: false
  • Supposed local time: 00:17

Joda Time API:

  • Default TimeZone: America/Rio_Branco
  • Standard Offset: -10800000
  • Offset: -10800000
  • Supposed local time: 00:17

Result:

Time and date reported by APIs now matches real time. Reported timezone (Brazil/Sao_Paulo, GMT-3:00)  is also correct, although different from system settings (South America/Brasilia, GMT-3:00). That is not an issue, since both timezones are synonyms.

After this investigation, it is not possible anymore to reproduce the previous behavior. Fortunately, neighbor desktop PCs were still available that presented the same issues and that allowed to continue the investigation.

Some further investigation revealed that:

  • People complain about wrong timezone issues on Sun Java Virtual Machine since JRE 1.3.
  • Several bug reports were submitted against Sun Java Virtual Machine during last ten years about wrong default timezone. Nearly all reports were rejected by Sun as unreproducible.

It is also important to know that:

  • Java implements its own timezone framework and does not rely to any system-dependent implementation. Timezone features vary too much across platforms and the Java API intends to leverage the differences.
  • Java timezone ids and definitions do not match system timezone ids and definitions. Java translates information queried from the underlying platform using a best effort approach heuristic.
  • If timezone information is not available from system, Java tries to infer timezone from locale settings, like country name.
  • One may override default timezone discovery from Java API by setting the user.timezone system property.

Still unsatisfied with the results, although a “solution” was found, we took some steps deeper towards the cause of the issue.

A look into the Windows XP registry revealed that certain registry patterns lead (or not) the Java Virtual Machine to fail to discover correct timezone.

This is the printout form the registry when the issue happens:

! REG.EXE VERSION 3.0

HKEY_LOCAL_MACHINE\SYSTEM\

CurrentControlSet\Control\TimeZoneInformation
Bias        REG_DWORD       0xb4
StandardName        REG_SZ  E. South America Standard Time
StandardBias        REG_DWORD       0x0
StandardStart       REG_BINARY      00000200030002003B003B00E7030000
DaylightName        REG_SZ  E. South America Daylight Time
DaylightBias        REG_DWORD       0xffffffc4
DaylightStart       REG_BINARY      00000A00030002003B003B00E7030000
ActiveTimeBias      REG_DWORD       0xb4
ActiveTime  REG_BINARY      92F8FFFF

After setting the timezone to another country and then back, the pattern changed as shown below and the issue ceased.

! REG.EXE VERSION 3.0

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
Bias        REG_DWORD       0xb4
StandardName        REG_SZ  E. South America Standard Time
StandardBias        REG_DWORD       0x0
StandardStart       REG_BINARY      00000200030017003B003B00E7030600
DaylightName        REG_SZ  E. South America Daylight Time
DaylightBias        REG_DWORD       0xffffffc4
DaylightStart       REG_BINARY      00000A00030017003B003B00E7030600
ActiveTimeBias      REG_DWORD       0xb4

Reverting the registry back to the prior pattern reproduces the issue. This means that we found a configuration that can really be reproduced on any machine (with Windows XP, of course)!

Analysis

Both Sun Java Virtual Machine JRE 1.5 and 1.6 query the Windows XP registry for timezone and use an heuristic to translate information as precise as possible into the Java timezone framework representation. Our investigation suggests that Java is not able to translate all possible valid patterns for the “StandardStart” and “DaylightStart” keys, causing a fallback to less accurate approach based on locale information.

Suggested workaround

  1. One may force the correct timezone with the -Duser.timezone=correct_timezone_id switch on command line. The get a list of all possible timezone IDs, call java.util.TimeZone.getAvailableIDs(). Unfortunately, this switch cannot be embedded into the .jar file.
  2. Or, within your main method, call as soon as possible, before any date/time related method call: System.setProperty(“user.timezone”, “correct_timezone_id”).
  3. On each date/time conversion to local time, pass as parameter the TimeZone object mapped to “correct_timezone_id”.

Conclusion

The investigation suggest that there is a bug in the Java implementation from Sun. The Java API is not able  to translate all possible Windows XP registry timezone patterns to equivalent timezone representation.

Even if your system is working perfectly at the moment, I sincerely suggest not to rely on TimeZone.getDefault() anymore. I recommend storing the correct timezone information within a property file that is read during application initialization or stored as user preferences. You never know when the timezone registry might change to a pattern that is not recognized by Java (e.g. automatic update from time server).

Future investigation would be appreciated to understand why the problematic patterns arose in the registry. These patterns are really observed to happen, and we found potentially hundreds of machines that introduced these patterns. There fore, it should be responsibility of the Java Virtual Machine to understand them.

The investigation should also be extended to other Java Virtual Machines not released by Sun.

4 Responses to Java and incorrect timezone on Windows XP

  1. Pingback: iastor.sys

  2. Olá,

    Já faz algum tempo que postou, mas, vc já olhou o arquivo jre/lib/tzmappings?

    Sds,

    Gerson.

  3. Dip Sarkar says:

    Hi,
    I have 2 installations of same JRE in the same timezone.
    I face the above issue on one installation, whereas the other installation works fine.

    I noticed the user.timezone is getting set automatically in the second case?

    Any ideas how Java sets the timezone automatically and sometimes does not?

    I do not want to use the user.timezone param, I want to set timezone ONCE for ALL across my System so that any instance of JVM gets that.

    BR,
    Dip

  4. Vladimir Lenin says:

    FYI, all I had to do to fix this was:

    1) double-click the windows clock (usu) in the lower-right corner of the screen

    2) go to Time Zone tab, select a different timezone, click ‘Apply’

    3) select the correct timezone, click ‘Apply’

    4) restart java app

    I don’t know how this will fare on a reboot, but it seems to update the registry time zone into something Java can understand.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 383 other followers

%d bloggers like this: