我从外部API收到UTC时间戳字符串,我需要将其存储为LocalDateTime。换句话说,如果时间戳在启用夏令时的时段内,则应将其调整为DST(通常是一个小时)。
我将传入的字符串解析为OffsetDateTime,然后将其转换为ZonedDateTime,然后转换为Instant。此时,DST时间已正确调整。但是,当我LocalDateTime从创建时Instant,它会丢失调整。
@Test
public void testDates() {
final DateTimeFormatter OFFSET_FORMAT = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXX");
final ZoneId zoneId = TimeZone.getDefault().toZoneId();
final String summerTime = "2019-09-11T10:00:00.000+0000";
final String winterTime = "2019-12-11T10:00:00.000+0000";
OffsetDateTime odtSummer = OffsetDateTime.parse(summerTime, OFFSET_FORMAT);
OffsetDateTime odtWinter = OffsetDateTime.parse(winterTime, OFFSET_FORMAT);
ZonedDateTime zdtSummer = odtSummer.toLocalDateTime().atZone(zoneId);
ZonedDateTime zdtWinter = odtWinter.toLocalDateTime().atZone(zoneId);
Instant instSummer = zdtSummer.toInstant();
Instant instWinter = zdtWinter.toInstant();
System.out.println("instSummer = " + instSummer); // instSummer = 2019-09-11T09:00:00Z
System.out.println("instWinter = " + instWinter); // instWinter = 2019-12-11T10:00:00Z
LocalDateTime ldtSummer = LocalDateTime.ofInstant(instSummer, zoneId);
LocalDateTime ldtWinter = LocalDateTime.ofInstant(instWinter, zoneId);
System.out.println("ldtSummer = " + ldtSummer); // ldtSummer = 2019-09-11T10:00
System.out.println("ldtWinter = " + ldtWinter); // ldtWinter = 2019-12-11T10:00
}
Run Code Online (Sandbox Code Playgroud)
我应该怎么做?我不想诉诸诸如重新解析之类的丑陋的东西Instant.toString()。
问题是您将输入转换为ZonedDateTime值的方式
ZonedDateTime zdtSummer = odtSummer.toLocalDateTime().atZone(zoneId);
ZonedDateTime zdtWinter = odtWinter.toLocalDateTime().atZone(zoneId);
Run Code Online (Sandbox Code Playgroud)
在这里,您说的是“获取的本地日期时间版本OffsetDateTime,并假装实际上是给定时区中的本地值”。因此,您最终得到的是“时区当地时间上午10点”,而不是“转换为本地时区的上午10点UTC”。
您写道:“此时,DST时间已正确调整”,但事实并非如此。您开始的值是“ 2019-09-11T10:00:00.000 + 0000”,但是当您打印时,Instant它的打印内容是“ 2019-09-11T09:00:00Z”。UTC上午10点和UTC上午9点不是同一时刻。
相反,您应该将转换OffsetDateTime为Instant-,因为这就是您真正解析的内容-,然后将其放在相关的时区中:
ZonedDateTime zdtSummer = odtSummer.toInstant().atZone(zoneId);
ZonedDateTime zdtWinter = odtWinter.toInstant().atZone(zoneId);
Run Code Online (Sandbox Code Playgroud)
或使用 OffsetDateTime.atZoneSameInstant
ZonedDateTime zdtSummer = odtSummer.atZoneSameInstant(zoneId);
ZonedDateTime zdtWinter = odtSummer.atZoneSameInstant(zoneId);
Run Code Online (Sandbox Code Playgroud)
请注意,从那回溯到瞬间以获得LocalDateTime-just use是没有意义的toLocalDateTime。如果需要所有相关类型,请使用以下适当的代码:
OffsetDateTime odtSummer = OffsetDateTime.parse(summerTime, OFFSET_FORMAT);
OffsetDateTime odtWinter = OffsetDateTime.parse(winterTime, OFFSET_FORMAT);
Instant instSummer = odtSummer.toInstant();
Instant instWinter = odtWinter.toInstant();
ZonedDateTime zdtSummer = instSummer.atZone(zoneId);
ZonedDateTime zdtWinter = instWinter.atZone(zoneId);
LocalDateTime ldtSummer = zdtSummer.toLocalDateTime();
LocalDateTime ldtWinter = zdtWinter.toLocalDateTime();
Run Code Online (Sandbox Code Playgroud)
如果您不需要Instant,只需:
OffsetDateTime odtSummer = OffsetDateTime.parse(summerTime, OFFSET_FORMAT);
OffsetDateTime odtWinter = OffsetDateTime.parse(winterTime, OFFSET_FORMAT);
ZonedDateTime zdtSummer = odtSummer.atZoneSameInstant(zoneId);
ZonedDateTime zdtWinter = odtWinter.atZoneSameInstant(zoneId);
LocalDateTime ldtSummer = zdtSummer.toLocalDateTime();
LocalDateTime ldtWinter = zdtWinter.toLocalDateTime();
Run Code Online (Sandbox Code Playgroud)