Java 8: calcular la diferencia entre dos ZonedDateTime

80

Estoy tratando de escribir un método para imprimir la diferencia horaria entre dos ZonedDateTime s, con respecto a la diferencia entre zonas horarias.

Encontré algunas soluciones, pero todas fueron escritas para trabajar con LocalDateTime .

Maggie Hill
fuente
2
Publique un ejemplo concreto de lo que desea lograr y obtenga como resultado.
JB Nizet
2
La respuesta de Michał es exactamente lo que esperaba. ¡Muchas gracias!
Maggie Hill

Respuestas:

102

Puede utilizar el método entre de ChronoUnit .

Este método convierte esos tiempos en la misma zona (zona desde el primer argumento) y después de eso, invoca hasta que el método declarado en la interfaz temporal :

static long zonedDateTimeDifference(ZonedDateTime d1, ZonedDateTime d2, ChronoUnit unit){
    return unit.between(d1, d2);
}

Dado que tanto ZonedDateTime como LocalDateTime implementan la interfaz temporal , también puede escribir un método universal para esos tipos de fecha y hora:

static long dateTimeDifference(Temporal d1, Temporal d2, ChronoUnit unit){
    return unit.between(d1, d2);
}

Pero tenga en cuenta que la invocación de este método para LocalDateTime y ZonedDateTime mezclados conduce a DateTimeException .

Espero eso ayude.

Michał Szewczyk
fuente
¿Hay alguna manera de obtener la diferencia entre dos tipos de ZDT donde el ZoneId es diferente entre los dos ZDT?
stanlick
@stanlick Sí: Duration.between( zdtA , zdtB )como se muestra en mi respuesta . Me imagino que el betweenmétodo simplemente llama ZonedDateTime::toInstant()a ambos.
Basil Bourque
73

tl; dr

Por horas, minutos, segundos:

Duration.between( zdtA , zdtB )  // Represent a span-of-time in terms of days (24-hour chunks of time, not calendar days), hours, minutes, seconds. Internally, a count of whole seconds plus a fractional second (nanoseconds).

Por años, meses, días:

Period.between(                  // Represent a span-of-time in terms of years-months-days. 
    zdtA.toLocalDate() ,         // Extract the date-only from the date-time-zone object. 
    zdtB.toLocalDate() 
)

Detalles

La respuesta de Michal S es correcta, mostrando ChronoUnit.

Duration Y Period

Otra ruta son las clases Durationy Period. Utilice el primero para períodos de tiempo más cortos (horas, minutos, segundos), el segundo para períodos más largos (años, meses, días).

Duration d = Duration.between( zdtA , zdtB );

Produzca una cadena en formato estándar ISO 8601 llamando toString. El formato es PnYnMnDTnHnMnSdonde Pmarca el comienzo y Tsepara las dos porciones.

String output = d.toString();

En Java 9 y versiones posteriores, llame a los to…Partmétodos para obtener los componentes individuales. Discutido en otra respuesta mía .

Código de ejemplo

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtStart = ZonedDateTime.now( z );
ZonedDateTime zdtStop = zdtStart.plusHours( 3 ).plusMinutes( 7 );

Duration d = Duration.between( zdtStart , zdtStop );

2016-12-11T03: 07: 50.639-05: 00 [América / Montreal] /2016-12-11T06:14:50.639-05:00 [América / Montreal]

PT3H7M

Vea el código en vivo en IdeOne.com .

Interval Y LocalDateRange

El proyecto ThreeTen-Extra agrega funcionalidad a las clases java.time. Una de sus clases útiles es Intervalrepresentar un lapso de tiempo como un par de puntos en la línea de tiempo. Otro es LocalDateRange, para un par de LocalDateobjetos. En contraste, las clases Period& Durationrepresentan cada una un lapso de tiempo que no se adjunta a la línea de tiempo.

El método de fábrica para Intervaltoma un par de Instantobjetos.

Interval interval = Interval.of( zdtStart.toInstant() , zdtStop.toInstant() );

Puede obtener un Durationde un Interval.

Duration d = interval.toDuration();

Tabla de clases de intervalo de tiempo en Java y en el proyecto ThreeTen-Extra


Acerca de java.time

El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como java.util.Date, Calendar, y SimpleDateFormat.

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Para obtener más información, consulte el tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .

Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No se necesitan cuerdas, no se necesitan java.sql.*clases.

¿Dónde obtener las clases java.time?

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time. Usted puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter, y más .

Albahaca Bourque
fuente
¿Dónde ves un ofmétodo de duración que toma dos instantes? Solo veopublic static Duration of(long amount, TemporalUnit unit)
Brian Gordon
@BrianGordon Corregido, reemplazando .ofcon .between. Gracias.
Basil Bourque
Duration funciona con ZonedDateTime mientras que Period funciona con LocalDate. es necesario realizar una llamada al método toLocalDate () en nuestro objeto zdt.
guillaume guerin
1
@guillaumeguerin Tienes razón. Arreglado mi ejemplo de código. Gracias.
Basil Bourque
Oh hombre muchas gracias, tu ejemplo es bastante bueno !!!!
Brendon Iwata