Joda时间:日期转换错误

时间:2014-03-27 06:51:15

标签: java timezone jodatime

我正在使用Joda Time 2.3将String转换为java.lang.Date。

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.3</version>
</dependency>

以下是一些测试代码:

System.out.println(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("1927-12-11 11:22:38"));
System.out.println(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("1927-12-11 11:22:38").toDate());

System.out.println(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("1937-12-11 11:22:38"));
System.out.println(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("1937-12-11 11:22:38").toDate());

在JDK 5和JDK 7下运行良好。但是在使用JDK 6时,结果是:

1927-12-11T11:22:38.000+08:05:57
Sun Dec 11 11:22:33 CST 1927 // lose 5 second
1937-12-11T11:22:38.000+08:00
Sat Dec 11 11:22:38 CST 1937

你看到第一次转换为java.lang.Date失去了5秒,但第二次转换是正确的。唯一的区别是年份数,第一个是1927年,第二个是1937年。1927年以下的所有年份都会导致错误。

这绝对是joda的错误。有人可以告诉我如何避免这个错误,或者我必须使用SimpleDateFormatter。

谢谢!

1 个答案:

答案 0 :(得分:5)

您是否看过关于上海时间的Jon Skeets answer?我想说,这不是一个错误,而是时区历史数据中的一个奇怪的条目。

请注意,tz历史数据应小心处理(不是可靠的来源,这里只是关于LMT的假设 - 中国的本地平均时间是根据上海经度计算的)。 IANA-tzdb仅在1970年之后才能生成可靠的数据。

修改

我已经为显式时区“亚洲/上海”测试了您的代码(在您的示例输出中符合时区名称CST)并获取:

DateTimeZone tz = DateTimeZone.forID("Asia/Shanghai");

System.out.println(
  DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
  .withZone(tz)
  .parseDateTime("1927-12-11 11:22:38"));
System.out.println(
  DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
  .withZone(tz)
  .parseDateTime("1927-12-11 11:22:38")
  .toDate());

System.out.println(
  DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
  .withZone(tz)
  .parseDateTime("1937-12-11 11:22:38"));
System.out.println(
  DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
  .withZone(tz)
  .parseDateTime("1937-12-11 11:22:38")
  .toDate());

输出:

1927-12-11T11:22:38.000+08:05:52
Sun Dec 11 04:16:46 CET 1927 // toString() prints in standard time zone
1937-12-11T11:22:38.000+08:00
Sat Dec 11 04:22:38 CET 1937 // toString() prints in standard time zone

与结果相比有5秒的小差异,因为我们使用不同版本的时区数据库(+08:05:52与+08:05:57相比更改为tzdb的版本2013a -see也Paul Eggert的实验性存储库中的this commit JDK版本从5更改为6或更高版本也可能涉及此更改 - 因此SimpleDateFormat的结果相同。就这些。我不认为您会使用SimpleDateFormat获得更好的结果,请参阅此处:

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setLenient(false);
df.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
Date d = df.parse("1927-12-11 11:22:38");
System.out.println(d);
long offset = TimeZone.getTimeZone("Asia/Shanghai").getOffset(d.getTime()) / 1000;
System.out.println(offset);
int offsetHours = (int) (offset / 3600);
long minutes = (offset % 3600);
System.out.println(offsetHours + ":0" + minutes / 60 + ":" + (minutes % 60));

你获得相同的偏移量,即我的tz版本08:05:52 java.util.Date.toString()中无法读取的内容 - 输出(只有CST作为时区名称)。 因此,与JodaTime相比,偏移没有差异,只要JDK和JodaTime使用相同的tzdb版本