Estoy tratando de convertir XMLGregorianCalendar que se envía en formato GMT / UTC a Java 8 LocalDateTime en la zona horaria de América / Los_Angeles sin suerte.

Esto es lo que intenté y no pude convertir la hora a la hora del Pacífico.

//xmlDate is 2017-11-13T00:00:00Z
ZonedDateTime zDateTime = xmlDate.toGregorianCalendar().toZonedDateTime().toLocalDateTime().atZone(ZoneId.of("America/Los_Angeles"));
LocalDateTime localDateTime = zDateTime.toLocalDateTime(); 
//Expected localDateTime is 2017-11-12T16:00. But I only get 2017-11-13T00:00

¿Qué me estoy perdiendo?

5
Ram 12 nov. 2017 a las 06:53

2 respuestas

La mejor respuesta

atZone() no hace lo que crees que hace. Simplemente adjunta una zona horaria a una fecha sin preservar el instante en el tiempo. Debes hacerlo usando ZonedDateTime#withZoneSameInstant(), que mantiene el instante y modifica la zona:

public static void main(String[] args) throws Exception {
    XMLGregorianCalendar xc = DatatypeFactory.newInstance().newXMLGregorianCalendar(2017, 10, 13, 0, 0, 0, 0, 0);
    System.out.println(xc);
    GregorianCalendar gc = xc.toGregorianCalendar();
    System.out.println(gc);
    ZonedDateTime zdt = gc.toZonedDateTime();
    System.out.println(zdt);
    LocalDateTime ldt = zdt.withZoneSameInstant(ZoneId.of("America/Los_Angeles")).toLocalDateTime();
    System.out.println(ldt);
}
7
Jim Garrison 12 nov. 2017 a las 04:31

Utilice el patrón DateTimeFormatter para definir claramente el formato de fecha y hora, y con zoneId definido.

String xmlDate = "2017-11-13T00:00:00Z";

DateTimeFormatter formatInput =DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").withZone(ZoneId.of("UTC"));
DateTimeFormatter formatOutput =DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm").withZone(ZoneId.of("America/Los_Angeles"));

ZonedDateTime zoned = ZonedDateTime.parse(xmlDate,formatInput);

System.out.println("Output date and time: "+formatOutput.format(zoned));

Fecha y hora de salida: 2017-11-12T16: 00

-1
Shuyou 12 nov. 2017 a las 05:05