DateTimeFormatter 解析 - 时区名称和夏令时重叠时间

Gun*_*her 4 java java-time

为了提高某些遗留代码的性能,我正在考虑用 java.time.format.DateTimeFormatter 替换 java.text.SimpleDateFormat。

执行的任务之一是解析使用 java.util.Date.toString 序列化的日期/时间值。使用 SimpleDateFormat,可以将它们转回原始时间戳(忽略小数秒),但是在尝试使用 DateTimeFormatter 执行相同操作时,我遇到了问题。

使用任一格式进行格式化时,我的本地时区会显示为 CET 或 CEST,具体取决于夏令时是否对要格式化的时间有效。然而,在解析时,DateTimeFormatter 似乎对 CET 和 CEST 的处理方式相同。

这会产生夏令时结束时发生重叠的问题。格式化时,02:00:00 创建两次,时间间隔一小时,但使用 CEST 和 CET 时区名称 - 这很好。但在解析时,这种差异无法收回。

这是一个例子:

long msecPerHour = 3600000L;
long cet_dst_2016 = 1477778400000L;
DateTimeFormatter formatter =
    DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
ZoneId timezone = ZoneId.of("Europe/Berlin");
for (int hours = 0; hours < 6; ++hours) {
    long time = cet_dst_2016 + msecPerHour * hours;
    String formatted = formatter.format(Instant.ofEpochMilli(time).atZone(timezone));
    long parsedTime = Instant.from(formatter.parse(formatted)).toEpochMilli();
    System.out.println(formatted + ", diff: " + (parsedTime - time));
}
Run Code Online (Sandbox Code Playgroud)

这导致

Sun Oct 30 00:00:00 CEST 2016, diff: 0
Sun Oct 30 01:00:00 CEST 2016, diff: 0
Sun Oct 30 02:00:00 CEST 2016, diff: 0
Sun Oct 30 02:00:00 CET 2016, diff: -3600000
Sun Oct 30 03:00:00 CET 2016, diff: 0
Sun Oct 30 04:00:00 CET 2016, diff: 0
Run Code Online (Sandbox Code Playgroud)

它表明,尽管时区名称不同,但第二次出现的 02:00:00 的处理方式与第一次出现的情况相同。所以结果实际上相差了一个小时。

显然,格式化字符串具有所有可用信息,并且 SimpleDateFormat 解析实际上尊重它。是否可以使用 DateTimeFormatter 以给定的模式进行格式化和解析?

Jod*_*hen 7

对于具体情况是可以的:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendPattern("EEE MMM dd HH:mm:ss ")
    .appendText(OFFSET_SECONDS, ImmutableMap.of(2L * 60 * 60, "CEST", 1L * 60 * 60, "CET"))
    .appendPattern(" yyyy")
    .toFormatter(Locale.ENGLISH);
Run Code Online (Sandbox Code Playgroud)

这将精确的偏移量映射到预期文本。当您需要处理多个时区时,这种方法就会失败。

要正确完成这项工作,需要更改 JDK

  • 也谢谢您提交 JDK 问题。事实上,我还必须支持其他时区(例如 PDT/PST),因此我将坚持使用 SimpleDateFormat 解析包含“z”说明符的模式。 (2认同)