Current time zone in Java
Many programs need to be able to find out the current time of the computer they are running on, and its time zone, without hard coding it. For this purpose Java has the concept of default time zone which is an instance of
TimeZone class which is returned by
java.util.TimeZone.getDefault() . However, this time zone has often been incorrect on Windows computers. I first bumped into this problem in the beginning of 2014. I developed a Java desktop application which involved displaying the current time. On Linux, the displayed time was fine but on Windows XP the Java default time zone was incorrect, not Asia/Jerusalem but rather America/Bahia which was 5 hours off.
An internet search showed a long history of similar complaints on Java incorrectly reading the default time zone on Windows. The most clear and comprehensive account I have found, was due to Daniel Ferbers of Brasil, dated 2010. Among other things, this account details how time zone information in the registry is getting corrupt. Among other accounts are a Java Forums report of 2009 and a discussion of Sun and Oracle bugs (2010, Syngapore). Here is a more recent 2012 report from India and 2013 report.
I have found also a brief IBM report of 2009.
In June – July 2014 this bug stopped showing up any more on my Windows XP computer, apparently, due to a Java update from Oracle.
There is a similar problem with time redirection on terminals running on Windows 2008 servers which is reported here and it has an unresolved bug report on Oracle, (reported 2011, unresolved as I write it in July 2014).
What happens, in brief, is that Java maintains its own time zone database (containing the info about all daylight savings time changes in all regions of the world) and goes to Windows registry to find which time zone the computer is using; this is the picture that transpires from Daniel Ferbers’ account.
There are two issues here: (1) how to find the current time zone on a Windows computer, and (2) the overall design of Java time zones attempting to be smarter than the computer they run on. We shall consider each issue separately.
How to find the current time zone on Windows
Microsoft specifications mention three different ways to do this:
- The time zone information is written in the registry.
- There are time zone functions in the native API, the C runtime library.
- There are time zone functions in managed API which is based on .NET Framework – Microsoft Common Language Runtime (CLR).
It appears that none of these approaches is good for Java purposes, as I shall try to explain below.
Time zone in Windows registry
The first way to find out the current time zone on Windows is through the registry.
Microsoft has a specification how time zone information is written in the registry; see also here. (The place where the current time zone information is written in the registry is indicated in Daniel Ferber’s account.)
However, the past shows that this method is unreliable (see Daniel Ferbers’ account), and it is not clear whether it will be reliable in the future, as, on one hand, Microsoft may change the specifications, and on the other, letting us use the registry time zone information is clearly not a priority for Microsoft.
On the other hand, we see that Windows computers show their local times consistently according to the time zone that is set on them; this shows that Windows do not go to registry to get the current time, or go in some limited circumstances (e.g., when the system starts up – I am just guessing).
This takes us to other approaches that use Windows API.
The second way to find out the current time zone on Windows is the native API.
I tried to create a workaround of this bug using JNI which allows calling a native library from Java code.
In Java code it is easy to find out the operating system name and the platform (32 or 64 bit).
If it turns out that the system is Windows, one can use JNI to call a native library that would call Windows API functions to find out the current time zone offset.
In fact, there is a published C code for finding the current time zone offset, due to peterchen which uses just three function calls:
The native API that provides the time and time zone functions, is Microsoft Visual C runtime library; it is implemented in msvcrt.dll in its various versions.
For Visual C/C++ versions 4.2 to 6, the operating system and the user programs called the same DLL for C run-time library functions – which is the most reasonable solution since the functions are the same.
Beginning with Visual C/C++ 7.0 (Visual Studio .NET), Microsoft separated the libraries, declaring that msvcrt.dll is for operating system usage only and users should use another library, msvcr70.dll, msvcr71.dll, etc, through msvcr110.dll, and either package it with their own files or install side-by-side. The reason for this divergence is that Microsoft included other functionalities in msvcrt – such as structured exception handling, see this article on kobyk.wordpress.com.
One of gcc compilers on Windows is provided by MinGW, Minimalist GNU for Windows; it links user programs with the system copy of msvcrt.dll (and other similar DLLs that existed before msvcrt.dll on Windows 9x) thus removing the need for developers to include msvcrxx.dll in their distributions. In this way it also resolves GPL-related legal problems (any code licenced under GPL needs to include the source of all its distributions and thus cannot distribute any Microsoft DLLs). For this purpose, they perform admirable work of keeping track of various versions of msvcrt.dll released by Microsoft, and testing against them.
People say on the net that msvcrt is unreliable, see, e.g., the answer to this Stack Overflow question and, unfortunately, I can confirm this as you will see below.
I tried to implement the simple solution for finding the current time zone offset as suggested by peterchen, see above. On my Windows XP SP3 computer running Eclipse 4.3.2 with MinGW this solution worked fine. However, when I tried to implement the same solution on a Windows Server 2008 Datacenter v 6.0 (build 6002 SP2) 64 bit on Amazon Web Services with Microsoft Windows SDK 7.1 64 bit, I found that
gmtime() operated incorrectly (it subtracted two hours from my current Jerusalem time to get GMT while Daylight Savings Time was in effect and the current offset was actually three hours; my desktop on that computer showed the correct time).
People (and Microsoft) suggest finding a good version of msvcrt.dll (or msvcrxx.dll) and packaging it with their programs, or compiling against it statically.
However, my gut feeling is pessimistic as we do not know where the problem is, in msvcrt or in some other Microsoft dll it calls.
For this reason one would have to test the good version against all operating systems that people use (and that still starts at least with Windows XP).
It is likely that one version of msvcrt.dll would not work with all operating systems, so that one would need a few versions that would cover different operating systems.
All this would still not guarantee forward compatibility: a next version of Windows might not work with any of these.
My conclusion is that I cannot say that the native API is a reliable solution to find the current time zone from Java.
The big question is, how could Microsoft consistently release buggy msvcrt.dll without so much public outcry?
The only answer I have, is that all time-related functions of the C runtime library are not used that much; instead, people write their code that deals with any time-related issues in some higher-level languages such as C# or Visual Basic (both based on .NET framework of Microsoft), or Java.
Microsoft, on their side, encourage transition to .NET-based languages, and for this reason it is not in its interest to invest in the C runtime library.
Managed (.NET) API
With all these explanations, it appears that the only reliable method to find out the current time zone on Microsoft might be by using its .NET API.
This can be done easily by using
TimeZone.CurrentTimeZone property to get the current time zone, and then calling
TimeZone.GetUtcOffset(DateTime.Now) to get the current UTC offset; all this runs on all versions of .NET starting with version 1.1.
The problem with this approach is that .NET is not forward compatible: one needs a few versions of the code to run on all existing versions of .NET starting with 1.1, and when the next version of .NET is released, none of these versions of your code will run on it: even if one of them can run, one needs to declare its number in
app.config as explained here.
An alternative solution is to require all the clients install a certain version of .NET but that really contradicts the idea of portability of Java.
What to do?
We are now left with the question: what to do if I develop a Java application (or an applet) that needs to know the current time zone?
It seems that the easiest way for a Java program on Windows to use the current time reliably is to use the Java’s default time zone – from which we have started this discussion – and give the user a possibility to change the time zone if the program detects it incorrectly.
E.g., a GUI button that would give a choice of time zones known to Java, or a possibility to enter the current time zone offset, or both.
©Baruch Youssin 2014