¿Cómo puedo convertir una cadena a un UTC LocalDateTime con ajuste de horario de verano?

Chris:

Estoy recibiendo una cadena de marca de hora UTC de una API externa, y tengo que guardarlo como LocalDateTime. En otras palabras, si la marca de tiempo está dentro de un período en el que el horario de verano está activo, se debe ajustar para horario de verano (por lo general por una hora).

Me analizar la cadena entrante a una OffsetDateTime, que luego se convierten en una ZonedDateTime, y luego a una Instant. En este punto, el tiempo de horario de verano se ajusta correctamente. Pero cuando creo una LocalDateTimede la Instant, pierde el ajuste.

  @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
  }

¿Cómo debería hacer esto? No quiero que recurrir a algo feo como re-análisis Instant.toString().

Jon Skeet:

El problema es la forma en que está convirtiendo las entradas a ZonedDateTimelos valores

ZonedDateTime zdtSummer = odtSummer.toLocalDateTime().atZone(zoneId);
ZonedDateTime zdtWinter = odtWinter.toLocalDateTime().atZone(zoneId);

Aquí está diciendo "tomar la versión de fecha y hora local del OffsetDateTime, y pretender que era en realidad un valor local en la zona de tiempo determinado". Así que terminan con "hora local 10 de la zona horaria" en lugar de "UTC 10am, convertida a la zona horaria local".

Usted escribió que "En este punto, el tiempo de horario de verano se ajusta correctamente" - pero no lo es. Que se inició con un valor de "2019-09-11T10: 00: 00.000 + 0.000", pero cuando se imprime el Instantque está imprimiendo "2019-09-11T09: 00: 00Z". 10 a.m. GMT y 09 a.m. GMT no son el mismo instante.

En su lugar, deberá convertir la OffsetDateTimea una Instant- ya que es lo que realmente ha analizado sintácticamente - y luego poner que en la franja horaria correspondiente:

 ZonedDateTime zdtSummer = odtSummer.toInstant().atZone(zoneId);
 ZonedDateTime zdtWinter = odtWinter.toInstant().atZone(zoneId);

O utilizar la OffsetDateTime.atZoneSameInstant

 ZonedDateTime zdtSummer = odtSummer.atZoneSameInstant(zoneId);
 ZonedDateTime zdtWinter = odtSummer.atZoneSameInstant(zoneId);

Nota que hay a continuación, no tiene sentido ir desde que volver a un instante para obtener el LocalDateTime- solo uso toLocalDateTime. Si desea que todos los tipos pertinentes, aquí está el código apropiado:

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

Si no necesita el Instant, simplemente:

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

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=331028&siteId=1
Recomendado
Clasificación