我在一些日期解析和从我的格式中获取正确的日期/时间方面遇到了一个相当棘手的问题。这是进行格式化的代码(精简版)
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()));
只是为了确保事情匹配。“正确”的解决方法是在应用启动时明确设置系统默认时区。