java incorrect timezone
I have an instance of Java which seems to be using a completely incorrect time zone. Instead of using the Austr开发者_如何学Calia/Sydney time zone which Windows is using, it is using the America/Caracas time zone.
I checked the Windows time through the system clock firstly, then checked HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/
and ControlSet001
, ControlSet002
. All are set to a Sydney time zone.
Does anybody know if this is a bug in Java, or if it is referring to a time set elsewhere?
Java version is 1.6.0_06
Ensure you set the timezone for the JVM when starting the application:
-Duser.timezone="Australia/Sydney"
Check information on the following link:
http://techtavern.wordpress.com/2010/04/15/java-and-incorrect-timezone-on-windows-xp/
It shows, that there is a bug in JVM, causing reading incorrect default timezone from windows registry. There is no bug fix yet.
You should update your JRE/SDK, but TZUpdater may be sufficient.
Try in your app to get default timezone, or set timezone manually (commented line).
Little example of mine:
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Locale locale = Locale.getDefault();
TimeZone localTimeZone = TimeZone.getDefault();
//TimeZone localTimeZone = TimeZone.getTimeZone("Australia/Sydney");
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, locale);
dateFormat.setTimeZone(localTimeZone);
Date rightNow = new Date();
System.out.println(locale.toString() + ": " + dateFormat.format(rightNow));
}
}
I had the very same problem recently, apparently this is caused by an ambiguity how Windows represents its timezone settings in the registry and Java failing to interpret it correctly.
More details can be found in this article, which also describes "cures" for the affected machine:
- 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.
There is a history of such problems that come and go, and no reasonable solution. See more here: Java incorrect time zone bug on Windows
Edit: Answering Tom and francis: In brief, Java runtime has hard time doing the job of correctly finding out the current time zone on the computer.
Windows registry information on the time zones has been unreliable, and the same for native windows API which relies on msvcrt.dll and various msvcrxx.dll . There is also Managed (.NET) API which requires installing a certain version of .NET Framework which contradicts portability of Java.
Thus, developers of Java runtime have hard time with the current time zone on Windows, and this may continue until Microsoft has some reason to cooperate.
If you want your Java application work correctly in any time zone, give users a possibility to correct the time zone via GUI.
I had the same error, while I was setting my timezone to Malay Peninsula Standard Time, the JVM gave me Venezuela Time timezone.
The following fix works for me:
In the registry editor, edit your timezone to another timezone (I was trying to put another text like "Singapore Time". You can find the registry here:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/TimeZoneInformation
And then, I reset it back to my desired timezone using Control Panel, Date and Time setting. When I check back to the registry editor, I can see it is reverted to Malay Peninsula Standard Time. And my JVM reads it correctly now...
tl;dr
A Java programmer should never rely on the JVM’s current default time zone.
- Always specify a proper time zone name in the format of
Continent/Region
, such asAfrica/Casablanca
. - Always confirm the desired/expected zone with the user, when important.
Proper time zone names
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 2-4 letter abbreviation such as CST
, EST
or IST
as they are not true time zones, not standardized, and not even unique(!). For example, if you use IST
for Ireland Standard Time, you might instead get India Standard Time with surprising results.
ZoneId z = ZoneId.of( "America/Montreal" ) ; // Or "Pacific/Auckland", "Africa/Tunis", etc.
Specify time zone
Never rely on the JVM’s current default time zone. That default value can change.
- As the other Answers explain, most JVMs by default use the host OS’ default time zone in play when the JVM launched.
- Or the script launching the JVM may pass a flag to specify a default time zone at launch.
- And during runtime(!) the JVM‘s current default time zone can be set by any code in any thread of any app within the JVM calling
TimeZone.setDefault
. (By the way,TimeZone
is obsoleted byZoneId
&ZoneOffset
, except for that setter method which should never be called except in the most extreme situation.) - And, of course, the user or sysadmin can change their current default time zone on the host OS which is not detected by running JVMs in most implementations as far as I know.
So, for all those reasons, the JVM’s current default time zone is completely out of the hands of the programmer, and even worse, can change dynamically at runtime. Therefore, using current default is not reliable.
Use the JVM’s current default time zone for only the most casual of purposes. For anything that matters, you simply must confirm the intended zone with the user. This is an inconvenient truth often resisted by programmers, but true nonetheless.
Locale
Tip: Ditto for Locale
. The JVM’s current default locale may or may not match that of the host OS, can change at any moment, and is therefore unreliable. Always confirm the desired/expected Locale
with the user.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, SimpleDateFormat
, and java.util.TimeZone
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
In case time zones seem completely gone, at least in my case that Java 5 was used on a legacy system, make sure that the proper file exists in %JAVA_HOME%\jre\lib\zi folder. For instance, me, I couldn't make Europe/Athens work for the life of me. It turns out that the file %JAVA_HOME%\jre\lib\zi\Europe\Athens was missing (those directories that refer to continents were completely empty in the JDK I was using..) - did a comparison with a freshly downloaded JDK 1.5.0_22 from Oracle.
I solved that error adding this to my DB URL:
?useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
精彩评论