我有一个Java实例,似乎使用了完全错误的时区。它使用的是美国加拉加斯时区,而不是Windows正在使用的澳大利亚/悉尼时区。
我首先通过系统时钟检查了Windows时间,然后检查了 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/
和 ControlSet001
、ControlSet002
。所有这些都设置为悉尼时区。
是否有人知道这是否是Java的一个bug,或者它是在引用其他地方设置的时间?
Java版本是1.6.0_06
确保在启动应用程序时为JVM设置时区:
-Duser.timezone="Australia/Sydney"
请查看以下链接获取信息:
http://techtavern.wordpress.com/2010/04/15/java-and-incorrect-timezone-on-windows-xp/
该链接显示,JVM存在一个错误,导致从Windows注册表中读取不正确的默认时区。目前还没有修复此错误的方法。
尝试在您的应用程序中获取默认时区,或手动设置时区(已注释行)。
以下是我的一个例子:
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));
}
}
setDefault
的 Java 代码来覆盖这些设置。请注意是在运行时调用 setDefault
。 - Basil Bourque
- 手动更改日期/时间,然后改回原来的正确时间。
- 更改时区,然后改回原来的时区。
- 从时间服务器请求自动时间更新。
这样的问题历史悠久,来来去去,始终没有一个合理的解决方案。在此处查看更多信息:Java在Windows上错误的时区错误
编辑:回答Tom和Francis:简而言之,Java运行时很难正确地找到计算机上的当前时区。
Windows注册表中关于时区的信息不可靠,并且本机Windows API也是如此,它依赖于msvcrt.dll和各种msvcrxx.dll。还有管理的(.NET)API需要安装某个版本的.NET Framework,这与Java的可移植性相矛盾。
因此,Java运行时的开发人员在Windows上的当前时区方面面临困难,这可能会一直持续,直到微软有某些合作的原因。
如果您希望Java应用程序在任何时区下正常工作,请为用户提供通过GUI更正时区的可能性。
如果时区似乎完全消失了,在我的情况下,Java 5被用在一个传统系统上,请确保%JAVA_HOME%\jre\lib\zi文件夹中存在正确的文件。例如,我无论如何都无法让Europe/Athens工作。结果发现%JAVA_HOME%\jre\lib\zi\Europe\Athens文件丢失了(我使用的JDK中那些指向大陆的目录完全是空的...)- 与Oracle新下载的 JDK 1.5.0_22进行了比较。
我通过将以下内容添加到我的数据库URL中解决了该错误:
?useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
我曾经遇到过同样的错误,当我将时区设置为马来半岛标准时间时,JVM给了我委内瑞拉时间时区。
以下修复方法适用于我:
在注册表编辑器中,将您的时区更改为另一个时区(我试图输入另一个文本,如“新加坡时间”)。您可以在此处找到注册表:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/TimeZoneInformation
然后,我使用控制面板、日期和时间设置将其重置回所需的时区。当我再次检查注册表编辑器时,我可以看到它已恢复为马来半岛标准时间。现在我的JVM正确读取它了...
Java程序员不应该依赖于JVM的当前默认时区。
洲/地区
的格式,例如Africa/Casablanca
指定一个正确的时区名称。指定一个洲/地区
的格式,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
作为正确的时区名称。永远不要使用2-4个字母的缩写,如CST
,EST
或IST
,因为它们不是真正的时区,没有标准化,甚至不是唯一的!例如,如果您使用IST
表示爱尔兰标准时间,则可能会意外地得到印度标准时间。
ZoneId z = ZoneId.of( "America/Montreal" ) ; // Or "Pacific/Auckland", "Africa/Tunis", etc.
永远不要依赖 JVM 的当前默认时区。默认值可能会发生变化。
TimeZone.setDefault
设置。(顺便说一句,TimeZone
已被 ZoneId
& ZoneOffset
废弃,除了那个 setter 方法外,应该只在最极端的情况下调用它。)因此,出于所有这些原因,JVM当前的默认时区完全不受程序员控制,更糟糕的是,它甚至可以在运行时动态更改。因此,使用当前默认值是不可靠的。
仅在最轻松的情况下使用JVM的当前默认时区。对于任何重要的事情,您必须与用户确认所需的时区。这是程序员经常抵制但却是真实的不便之处。
提示:对于本地化(Locale)
也同理。JVM当前的默认Locale可能与主机操作系统不匹配,随时可能更改,并且因此不可靠。始终与用户确认所需/预期的Locale
。
java.time框架已经内置于Java 8及以后版本中。这些类替代了老旧的、麻烦的日期时间类,如legacy java.util.Date
, Calendar
, SimpleDateFormat
, 和 java.util.TimeZone
。
Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。
想要了解更多,请参阅 Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是 JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。无需字符串,也不需要 java.sql.*
类。
如何获取 java.time 类?
ThreeTen-Extra 项目通过扩展 java.time 的类库提供了一些额外的类。该项目是用于可能未来加入 java.time 的试验场。您可以在这里找到一些有用的类,例如 Interval
, YearWeek
, YearQuarter
, 和更多。
EST
或IST
这样的 2-4 个字母的缩写不是真正的时区,没有标准化,甚至不是唯一的!请以大陆/地区
的格式指定一个正确的时区名称,例如America/Montreal
、Africa/Casablanca
或Pacific/Auckland
。 - Basil Bourque