在我的客户端,我有这段代码:
System.out.println("Java tz: " + TimeZone.getDefault());
System.out.println("Joda tz: " + ISOChronology.getInstance());
这两条线一个接一个地运行。我从不手动设置时区或user.timezone
,只需依靠从OS&读取的默认值。本地系统。
执行时,他们会产生:
Java tz: sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
Joda tz: ISOChronology[America/Phoenix]
系统时区确实是凤凰城,而不是UTC。 Joda怎么能正确,JDK错了?
编辑:这是Windows 7 x64主机,JRE是1.6.22 x64。
编辑2 :不要尝试重现它。它只会在某些系统上失败,而不是所有系统(就像我们的3k用户群中的几十个)。我已经知道Joda检查user.timezone
然后TimeZone.getDefault()
。所以我正在寻找一个解释,说明我直接调用TimeZone
和Joda自己调用它有什么不同。
答案 0 :(得分:7)
当您说“从操作系统和本地系统读取默认值”时,没有一个明确定义的位置可以读取此默认值。甚至API文档本身都说
获取此主机的默认
TimeZone
。默认TimeZone
的来源可能因实施而异。
所以简单的答案就是Joda和你的JVM从不同的信息源推断出默认时区。需要记住的是默认是猜测,而不是JVM可以最终获得访问权限的内容。
对于Linux上的Sun 1.5.0_06 JVM,使用以下顺序:
Joda 1.6.2使用:
user.timezone
。null
或不是有效标识符,则使用JDK的TimeZone
默认值。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()
,它可能会在其他线程中显示,也可能不会显示,具体取决于他们是否已经查找了该版本。如果你通过调试调用得到明显异常的结果,很可能只是因为不同的线程可以有不同的默认时区。