Joda Time的Java时区问题



我在一些日期解析和从格式中获取正确的日期/时间方面遇到了一个相当麻烦的问题。这是进行格式化的代码(浓缩版)

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
log.debug("Trying to convert {} using format {}.", val, "yyyy-MM-dd");
Date toDate = formatter.parseDateTime(inputText).toDate();
log.debug("Converted value to {}", toDate);

以下是值不正确的一些输出。此处的时区设置为EDT。(通过date命令和/etc/localtime符号链接进行检查。

13:14:53.618 [http-bio-8080-exec-13] DEBUG c.s.e.p.j.AbstractParamToObjectProvider - Trying to convert 2013-07-08 using format yyyy-MM-dd.
13:14:53.619 [http-bio-8080-exec-13] DEBUG c.s.e.p.j.AbstractParamToObjectProvider - Converted value to Sun Jul 07 20:00:00 EDT 2013

这是在Tomcat 7上使用OpenJDK 7的AWS-LINUX上运行的。我们有另一个在AWS上运行的实例,相同的代码产生了这个:

17:22:46.164 [http-bio-8080-exec-239] DEBUG c.s.e.p.j.AbstractParamToObjectProvider - Trying to convert 2013-07-08 using format yyyy-MM-dd.
17:22:46.165 [http-bio-8080-exec-239] DEBUG c.s.e.p.j.AbstractParamToObjectProvider - Converted value to Mon Jul 08 00:00:00 UTC 2013

这台机器上的时区设置为UTC。

在我的本地机器上,输出也是正确的(回到EDT,在OSX上运行oracles JDK):

13:24:55.967 [ajp-bio-8009-exec-176] DEBUG c.s.e.p.j.AbstractParamToObjectProvider - Trying to convert 2013-07-08 using format yyyy-MM-dd.
13:24:56.089 [ajp-bio-8009-exec-176] DEBUG c.s.e.p.j.AbstractParamToObjectProvider - Converted value to Mon Jul 08 00:00:00 EDT 2013

同样,三个位置的代码都相同。我一辈子都不明白为什么我们有一个例子的行为与其他人不同。我将添加更多的调试输出,试图缩小它的范围,但现在我运气不好。

另外,还有一个有趣的地方。在Tomcat之外的错误机器上运行,使用相同的jdk和以下代码,我得到了我所期望的:

DateTimeFormatter f = DateTimeFormat.forPattern("yyyy-MM-dd");
DateTime parseDateTime = f.parseDateTime("2013-07-08");
System.out.println(parseDateTime.toDate());

输出:

Mon Jul 08 00:00:00 EDT 2013

更新

Joda似乎没有使用系统默认时区。以下是我输出数据的方式:

log.debug("Using joda timezone of: {}", DateTimeZone.getDefault());
log.debug("Default timezone of: {}", TimeZone.getDefault());

这是输出:

AbstractParamToObjectProvider - Using joda timezone of: UTC
AbstractParamToObjectProvider - Default timezone of: sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]

其中一个与另一个不匹配。。。有什么想法吗?

解决方案

乔恩的回答是正确的,但这是最后的结论。

不知怎的,user.timezone被设置为UTC,Joda正在使用它,而默认的timezone没有(使用系统时区)。对于一个补丁,我做了以下操作:

DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault()));

只是为了确保匹配。"正确"的解决方案是在应用程序启动时显式设置系统默认时区。

Joda Time经过以下步骤:

  • 使用user.timezone系统属性
  • 根据TimeZone.getDefault()的ID创建时区
  • 回退到UTC

TimeZone.getDefault()可能稍微复杂一点,尽管它在许多情况下也使用user.timezone

一种选择是在应用程序启动时显式将TimeZoneDateTimeZone的默认时区设置为UTC:对于web服务器,这是最合理的默认使用方式(尽管我个人更喜欢在适当的情况下显式说明时区)。

相关内容

  • 没有找到相关文章

最新更新