为什么 JodaTime 时区会改变日期时间?

Oll*_*e C 5 android jodatime android-jodatime

当字符串“2017-04-21T17:46:00Z”被传递到第一个方法时,生成的格式化日期字符串是“06:46 21 Apr 2017”。为什么小时移动了十一小时?输入字符串由 HTTP 服务器应用程序以 JSON 格式提供。我以为 Z 后缀指的是祖鲁语,即 GMT。

private static final String DATE_TIME_FORMAT = "hh:mm dd MMM yyyy";

public static String formatTimestamp(String dateTimestamp) {
    DateTime dateTime = getDateTimeFromTimestamp(dateTimestamp);
    DateTimeFormatter fmt = DateTimeFormat.forPattern(DATE_TIME_FORMAT);
    return fmt.print(dateTime);
}

private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
    return new DateTime(dateTimestamp);
}
Run Code Online (Sandbox Code Playgroud)

我怀疑它与时区有关,但不清楚如何或在哪里。该代码在英国的 Android 设备上运行,采用 GMT 时区。

小智 4

我用 java 7 和 joda-time 2.7 进行了测试(但不是 Android 版本)

这就是我重现问题的方法:

// changing my default timezone (because I'm not in UK)
DateTimeZone.setDefault(DateTimeZone.forID("Europe/London"));
// calling your method
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));
Run Code Online (Sandbox Code Playgroud)

输出是

2017 年 4 月 21 日 06:46

为了检查问题所在,我将日期格式更改为:

DATE_TIME_FORMAT2 = "hh:mm a dd MMM yyyy Z z zzzz";
Run Code Online (Sandbox Code Playgroud)

其中a表示“AM 或 PM”,Z是时区偏移量/id,z是时区“短”名称,zzzz是时区“长”名称。使用此格式,输出为:

2017 年 4 月 21 日 +0100 BST 英国夏令时间 06:46 PM

因此,创建的日期时间是下午 6 点,仅比输入提前一小时,而不是您想象的十一个小时(实际上,如果您将格式更改为HH而不是hh,则小时将18代替06)。

另请注意时区字段:+0100 BST British Summer Time。第一部分 ( +0100) 表示此时DateTime比 GMT 早一小时,并且BST British Summer Time表示处于英国夏令时


因此,为了让你的输出等于你的输入,你有两种选择:

1.将默认时区更改为 UTC:

DateTimeZone.setDefault(DateTimeZone.UTC);
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));
Run Code Online (Sandbox Code Playgroud)

输出将是:

2017 年 4 月 21 日 05:46

如果您想将小时更改为17:46,请更改日期格式,替换hhHH

2.使用DateTime接收 的构造函数DateTimeZone

private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
    // creates a DateTime in UTC
    return new DateTime(dateTimestamp, DateTimeZone.UTC);
}
Run Code Online (Sandbox Code Playgroud)

输出将与替代方案 1 相同,但在这种情况下,您不需要更改默认时区。

对我来说,替代方案 2 更有意义,因为:

  • 您不需要更改默认时区(这可能会导致应用程序的其他部分出现混乱)
  • 您已经知道此代码处理的所有日期均采用 UTC 时间(因为末尾有“Z”