为了提高一些遗留代码的性能,我正在考虑用 java.time.format.DateTimeFormatter 替换 java.text.SimpleDateFormat。
执行的任务包括解析使用 java.util.Date.toString 序列化的日期/时间值。使用 SimpleDateFormat,可以将它们转回原始时间戳(忽略小数秒),但是在尝试使用 DateTimeFormatter 执行相同操作时我遇到了问题。
当使用其中任何一种进行格式化时,我的本地时区被指示为 CET 或 CEST,具体取决于夏令时是否对要格式化的时间有效。然而,在解析时,CET 和 CEST 似乎被 DateTimeFormatter 视为相同。
这会在夏令时结束时产生重叠问题。格式化时,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));
}
结果
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
它表明,尽管时区名称不同,但第二次出现的 02:00:00 被当作第一次出现。因此,结果实际上偏离了一个小时。
显然,格式化字符串具有所有可用信息,SimpleDateFormat 解析实际上尊重它。是否可以使用 DateTimeFormatter 和给定的模式来回格式化和解析?
最佳答案
对于特定情况是可能的:
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);
这会将确切的偏移量映射到预期的文本。当您需要处理多个时区时,这种做法会失败。
要正确完成这项工作需要 JDK change .
关于java - DateTimeFormatter 解析 - 时区名称和夏令时重叠时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43102957/