1

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

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

这是使用 OpenJDK 7 在 Tomcat 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 这里在 OS X 上运行 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()));

只是为了确保事情匹配。“正确”的解决方法是在应用启动时明确设置系统默认时区。

4

1 回答 1

4

Joda Time 经历以下步骤:

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

TimeZone.getDefault()可能有点复杂,尽管它user.timezone在很多情况下也使用。

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

于 2013-08-30T19:48:24.657 回答