Java 8: diferencia entre dos LocalDateTime en varias unidades

Resuelto Tapas Bose asked hace 10 años • 12 respuestas

Estoy tratando de calcular la diferencia entre dos.LocalDateTime .

La salida debe tener el formato y years m months d days h hours m minutes s seconds. Esto es lo que he escrito:

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;

public class Main {

    static final int MINUTES_PER_HOUR = 60;
    static final int SECONDS_PER_MINUTE = 60;
    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;

    public static void main(String[] args) {
        LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
        LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

        Period period = getPeriod(fromDateTime, toDateTime);
        long time[] = getTime(fromDateTime, toDateTime);

        System.out.println(period.getYears() + " years " + 
                period.getMonths() + " months " + 
                period.getDays() + " days " +
                time[0] + " hours " +
                time[1] + " minutes " +
                time[2] + " seconds.");


    }

    private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
        return Period.between(dob.toLocalDate(), now.toLocalDate());
    }

    private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
        LocalDateTime today = LocalDateTime.of(now.getYear(),
                now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
        Duration duration = Duration.between(today, now);

        long seconds = duration.getSeconds();

        long hours = seconds / SECONDS_PER_HOUR;
        long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
        long secs = (seconds % SECONDS_PER_MINUTE);

        return new long[]{hours, minutes, secs};
    }
}

El resultado que obtengo es 29 years 8 months 24 days 12 hours 0 minutes 50 seconds. He comprobado mi resultado de este sitio web (con valores 12/16/1984 07:45:55y 09/09/2014 19:46:45). La siguiente captura de pantalla muestra el resultado:

Convertidor de época

Estoy bastante seguro de que los campos después del valor del mes son incorrectos en mi código. Cualquier sugerencia sería de gran ayuda.

Actualizar

Probé mi resultado en otro sitio web y el resultado que obtuve es diferente. Aquí está: Calcular la duración entre dos fechas. (resultado: 29 años, 8 meses, 24 días, 12 horas, 0 minutos y 50 segundos).

Actualizar

Como obtuve dos resultados diferentes de dos sitios diferentes, me pregunto si el algoritmo de mi cálculo es legítimo o no. Si uso los siguientes dos LocalDateTimeobjetos:

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

Entonces viene la salida:29 years 8 months 25 days -1 hours -5 minutes -10 seconds.

Desde este enlace debería ser 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds. Entonces el algoritmo también necesita manejar los números negativos.

Tenga en cuenta que la pregunta no es qué sitio me dio qué resultado, necesito conocer el algoritmo correcto y obtener los resultados correctos.

Tapas Bose avatar Sep 09 '14 21:09 Tapas Bose
Aceptado

Descubrí que la mejor manera de hacer esto es con ChronoUnit.

long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);
long hours = ChronoUnit.HOURS.between(fromDate, toDate);

La documentación adicional está aquí: Periodo y Duración

satnam avatar Nov 16 '2014 07:11 satnam

Desafortunadamente, no parece haber una clase periódica que abarque también el tiempo, por lo que es posible que tengas que hacer los cálculos por tu cuenta.

Afortunadamente, las clases de fecha y hora tienen muchos métodos de utilidad que lo simplifican hasta cierto punto. Aquí tienes una forma de calcular la diferencia, aunque no necesariamente la más rápida:

LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);

LocalDateTime tempDateTime = LocalDateTime.from( fromDateTime );

long years = tempDateTime.until( toDateTime, ChronoUnit.YEARS );
tempDateTime = tempDateTime.plusYears( years );

long months = tempDateTime.until( toDateTime, ChronoUnit.MONTHS );
tempDateTime = tempDateTime.plusMonths( months );

long days = tempDateTime.until( toDateTime, ChronoUnit.DAYS );
tempDateTime = tempDateTime.plusDays( days );


long hours = tempDateTime.until( toDateTime, ChronoUnit.HOURS );
tempDateTime = tempDateTime.plusHours( hours );

long minutes = tempDateTime.until( toDateTime, ChronoUnit.MINUTES );
tempDateTime = tempDateTime.plusMinutes( minutes );

long seconds = tempDateTime.until( toDateTime, ChronoUnit.SECONDS );

System.out.println( years + " years " + 
        months + " months " + 
        days + " days " +
        hours + " hours " +
        minutes + " minutes " +
        seconds + " seconds.");

//prints: 29 years 8 months 24 days 22 hours 54 minutes 50 seconds.

La idea básica es la siguiente: crear una fecha de inicio temporal y completar los años hasta el final. Luego ajuste esa fecha por la cantidad de años para que la fecha de inicio sea menos de un año desde el final. Repita esto para cada unidad de tiempo en orden descendente.

Finalmente, un descargo de responsabilidad : no tomé en cuenta diferentes zonas horarias (ambas fechas deben estar en la misma zona horaria) y tampoco probé/verifiqué cómo cambia el horario de verano u otros cambios en un calendario (como los cambios de zona horaria en Samoa) afectar este cálculo. Así que úselo con cuidado.

Thomas avatar Sep 10 '2014 08:09 Thomas

¡Debería ser más sencillo!

Duration.between(startLocalDateTime, endLocalDateTime).toMillis();

Puedes convertir milisegundos a la unidad que quieras:

String.format("%d minutes %d seconds", 
  TimeUnit.MILLISECONDS.toMinutes(millis),
  TimeUnit.MILLISECONDS.toSeconds(millis) - 
  TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
Zon avatar Dec 27 '2018 15:12 Zon

A continuación se muestra un ejemplo que utiliza Duración y TimeUnit para obtener el formato 'hh:mm:ss'.

Duration dur = Duration.between(localDateTimeIni, localDateTimeEnd);
long millis = dur.toMillis();

String.format("%02d:%02d:%02d", 
        TimeUnit.MILLISECONDS.toHours(millis),
        TimeUnit.MILLISECONDS.toMinutes(millis) - 
        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
        TimeUnit.MILLISECONDS.toSeconds(millis) - 
        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
Junior Batista avatar May 23 '2017 18:05 Junior Batista