5

当字符串“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);
}

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

4

2 回答 2

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"));

输出是

2017 年 1 月 21 日 06:46

为了检查出了什么问题,我将日期格式更改为:

DATE_TIME_FORMAT2 = "hh:mm a dd MMM yyyy Z z zzzz";

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

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

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

另请注意时区字段:+0100 BST British Summer Time. 第一部分 ( +0100) 表示这DateTime比格林威治标准时间早一小时,并且BST British Summer Time表示它处于英国的夏令时


因此,要让您的输出等于您的输入,您有两种选择:

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

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

输出将是:

2017 年 4 月 21 日 05:46

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

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

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

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

对我来说,备选方案 2 更有意义,因为:

  • 您不需要更改默认时区(这可能会导致应用程序的其他部分出现混乱)
  • 您已经知道此代码处理的所有日期都是 UTC 时间(因为最后是“Z”
于 2017-04-27T12:40:53.480 回答
1
于 2017-06-12T06:19:53.820 回答