在我的客户端,我有这个代码:
System.out.println("Java tz: " + TimeZone.getDefault());
System.out.println("Joda tz: " + ISOChronology.getInstance());
Run Code Online (Sandbox Code Playgroud)
这两条线一个接一个地运行.我从不设置时区或user.timezone手动,只依赖于从操作系统和本地系统读取的默认值.
执行时,它们会产生:
Java tz: sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
Joda tz: ISOChronology[America/Phoenix]
Run Code Online (Sandbox Code Playgroud)
系统时区确实是凤凰城,而不是UTC.Joda怎么能正确,JDK错了?
编辑:这是一个Windows 7 x64主机,JRE是1.6.22 x64.
编辑2:不要试图重现它.它只会在某些系统上失败,而不是所有系统(就像我们的3k用户群中的几十个).我已经知道了Joda检查user.timezone然后TimeZone.getDefault().所以我正在寻找一个解释,说明我TimeZone直接打电话和Joda独自完成之间有什么不同.
当您说"从操作系统和本地系统读取默认值"时,没有一个明确定义的位置可以读取此默认值.甚至API文档本身都说
获取
TimeZone此主机的默认值.默认的来源TimeZone可能因实施而异.
所以简单的答案就是Joda和你的JVM从不同的信息源推断出默认时区.需要记住的是,默认值是猜测,而不是JVM最终可以访问的内容.
对于Sun在Linux上的1.5.0_06 JVM,使用以下顺序:
Joda 1.6.2使用:
user.timezone.null有效标识符,TimeZone则使用JDK 默认值.UTC则使用.因此,如果你有JDK和Joda的上述版本,我建议user.timezone可以在你的环境中设置属性.但是,其他版本可能会使用其他算法来获取默认值.
编辑:在Sun的JDK 1.6.0_22中,默认搜索首先检查user.timezone属性,如果找不到,则查找user.country属性以获取国家/地区的默认值.如果两者均未设置,GMT则使用默认值.因此,您观察到的结果可能会随JVM版本而改变.
编辑2:如果你有两个源(实际上源都可用),那么你可以简单地追踪它!逐步执行Joda调用,看看它是否确实遵循java.util.TimeZone.getDefault(),并查看返回值是什么.然后直接调用JDK方法,看看你得到了什么.
查看JDK源代码,似乎通过可继承的本地线程访问默认时区.因此,如果有人在某处调用TimeZone.setDefault(),它可能会或可能不会在其他线程中可见,这取决于他们是否已经查找了该版本.如果你通过调试调用得到明显异常的结果,很可能只是因为不同的线程可以有不同的默认时区.