Java 8: diferencia entre dos LocalDateTime en varias unidades

266

Estoy tratando de calcular la diferencia entre dos LocalDateTime.

La salida debe ser del formato y years m months d days h hours m minutes s seconds. Aquí está 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 estoy obteniendo es 29 years 8 months 24 days 12 hours 0 minutes 50 seconds. He verificado 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:

Epoch Converter

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

Actualizar

He probado mi resultado de otro sitio web y el resultado que obtuve es diferente. Aquí está: Calcule 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 sobre qué sitio me dio qué resultado, necesito saber el algoritmo correcto y tener los resultados correctos.

Tapas Bose
fuente
Solo una suposición, pero ¿podría Period.between()aplicar algún redondeo?
Thomas
3
Acabo de ver el código una vez más y parece que el sitio web está mal (intente calcular usted mismo). Si omite la fecha, es decir, las diferencias en año, mes y día, obtendrá la hora de inicio 7:45:55y la hora de finalización 19:46:45(o 7:46:45PM). Entonces, la diferencia entre esos dos tiempos es de 12 horas, 0 minutos y 50 segundos y nunca 23 horas, 34 minutos y 12 segundos. Por lo tanto, su cálculo actual parece ser correcto, al menos en la parte del tiempo.
Thomas
1
Fenómeno interesante en ese sitio web: agregue 10 años a la fecha de inicio y la diferencia en horas cambia de 23 a 8, seguramente un signo de error.
Thomas
8
Tenga en cuenta que, dado que LocalDateTimeno tiene zona horaria, es posible que no haya una respuesta única. Incluso si asume que las zonas horarias de inicio y finalización son las mismas, en ciertas zonas las fechas como 2014-09-09 serán en horario de verano o en horario de verano y en otras no. Esto podría retrasar las cosas por una hora. Por lo tanto, calcular la diferencia con el segundo no tiene sentido a menos que esto se resuelva.
Stuart Marks
2
¿Entiende que el uso LocalDateTimearroja resultados poco realistas, ya que esa clase carece deliberadamente de cualquier concepto de zona horaria o compensación desde UTC? Para valores realistas, asigne una zona horaria a través ZoneIddel uso ZonedDateTime.
Basil Bourque

Respuestas:

163

Desafortunadamente, no parece haber una clase de período que abarque también el tiempo, por lo que es posible que tenga que hacer los cálculos por su cuenta.

Afortunadamente, las clases de fecha y hora tienen muchos métodos de utilidad que simplifican eso hasta cierto punto. Aquí hay una manera 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 esta: cree una fecha de inicio temporal y obtenga los años completos hasta el final. Luego ajuste esa fecha por el número de años para que la fecha de inicio sea inferior a un año desde el final. Repita eso para cada unidad de tiempo en orden descendente.

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

Thomas
fuente
1
Tiene la misma idea básica, por lo tanto, mi voto positivo, pero intente utilizar la misma entrada, de lo contrario, el resultado diferente es confuso.
Meno Hochschild
@MenoHochschild es la misma entrada, recién tomada de la actualización donde el OP tiene problemas con tiempos negativos. ;)
Thomas
1
Buen algoritmo, pero tipo incorrecto (ver descargo de responsabilidad de Thomas). Antes de hacer su cálculo, debe convertir sus variables LocalDateTime a ZonedDateTime usando la zona horaria predeterminada, por ejemplo (o cualquier zona horaria que necesite): ZonedDateTime fromZonedDateTime = fromDateTime.atZone (ZoneId.systemDefault ());
Tristan
2
@Thomas Su ejemplo también está utilizando Java 8, y la pregunta está etiquetada como java-8. De hecho, su ejemplo incluso está usando ChronoUnit:) pero haciendo el trabajo "a mano".
Eugene Beresovsky
3
@EugeneBeresovsky oh sí, tienes razón. Lo perdí por completo;) - Además de eso, aún tendría que restar las unidades más grandes del intervalo ya que, por ejemplo long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);, devolvería un número mayor que 59 para cualquier intervalo de al menos 1 hora, y eso no es lo que quiere el OP. Teniendo eso en cuenta, no podrás hacer 6 llamadas ChronoUnit#between()y terminar.
Thomas
503

Encontré que la mejor manera de hacerlo es con ChronoUnit.

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

Documentación adicional está aquí: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html

satnam
fuente
8
No veo una mejora real. En comparación con la respuesta aceptada Thomas' que acaba de reemplazar tempDateTime.until( toDateTime, ChronoUnit.YEARS)con ChronoUnit.YEARS.between(fromDate, toDate). Pero las líneas adicionales importantes como tempDateTime.plusYears( years )etc. faltan por completo en su respuesta, por lo que no ayuda al OP. ¡El algoritmo completo importa!
Meno Hochschild
9
Me gusta más, ya que es más breve y más legible. Esta es la mejor manera de encontrar la diferencia entre dos fechas.
Somaiah Kumbera
77
@SomaiahKumbera No, te pierdes por completo el punto crítico. El OP no quiere una duración en una sola unidad sino en múltiples unidades , y por lo tanto esta respuesta no es una respuesta real en absoluto. La preocupación del OP simplemente no se aborda. Sea tan amable de volver a leer la pregunta. (Muchos electores parecen haber entendido mal la pregunta).
Meno Hochschild
126
@MenoHochschild, creo que en realidad eres tú quien pierde el punto crítico. El OP recibió su respuesta hace más de un año. Las 36 mil personas que están viendo esta pregunta no se preocupan por la pregunta específica del OP. Fueron conducidos aquí por Google y mi respuesta les proporcionó lo que estaban buscando: una solución limpia y simple para obtener la diferencia entre dos fechas.
satnam
10
Necesitaba la diferencia de segundos entre dos fechas y comencé a implementar mi propia solución. En breve parece complejo y tomé google. La respuesta de satnam puede no responder la pregunta de OP, pero seguramente me ayudó mucho y apuesto a que muchos otros como yo.
Julian
43

Aquí hay un solo ejemplo que usa Duration 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
fuente
2
De hecho, es posible hacerlo de esta manera: String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());. Los métodos de parte le dan los números correctos para construir una cadena. Creo que es más legible.
Daantie
Nota al margen de mi comentario anterior: los métodos de las piezas solo están disponibles desde JDK 9 en adelante.
Daantie
40

¡Debería ser más simple!

Duration.between(startLocalDateTime, endLocalDateTime).toMillis();
Zon
fuente
1
Creo que esta es en realidad la solución semánticamente correcta a partir de Java 8. Y antes de esa versión, JodaTime hace lo mismo.
Vrakfall
9

TL; DR

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

y luego utilizar los métodos period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart().


Respuesta ampliada

Contestaré la pregunta original, es decir, cómo obtener la diferencia de tiempo entre dos LocalDateTimesen años, meses, días, horas y minutos, de modo que la "suma" (ver nota a continuación) de todos los valores para las diferentes unidades sea igual al total diferencia temporal, y tal que el valor en cada unidad es menor que el siguiente más grande unidad, es decir minutes < 60, hours < 24, y así sucesivamente.

Dado dos LocalDateTimes starty end, por ejemplo

LocalDateTime start = LocalDateTime.of(2019, 11, 29, 17, 15);
LocalDateTime end = LocalDateTime.of(2020, 11, 30, 18, 44);

podemos representar el intervalo de tiempo absoluto entre los dos con un — tal vez Durationusando Duration.between(start, end). Pero la unidad más grande que podemos extraer de un Durationdía son los días (como una unidad temporal equivalente a 24 h); consulte la nota a continuación para obtener una explicación. Para usar unidades más grandes (meses, años) podemos representar esto Durationcon un par de ( Period, Duration), donde Periodmide la diferencia hasta una precisión de días y Durationrepresenta el resto:

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

Ahora podemos simplemente usar los métodos definidos en Periody Durationpara extraer las unidades individuales:

System.out.printf("%d years, %d months, %d days, %d hours, %d minutes, %d seconds",
        period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(),
        duration.toMinutesPart(), duration.toSecondsPart());
1 years, 0 months, 1 days, 1 hours, 29 minutes, 0 seconds

o, usando el formato predeterminado:

System.out.println(period + " + " + duration);
P1Y1D + PT1H29M

Nota sobre años, meses y días

Tenga en cuenta que, según java.timela concepción, las "unidades" como "mes" o "año" no representan un valor temporal absoluto fijo; dependen de la fecha y el calendario, como lo ilustra el siguiente ejemplo:

LocalDateTime
        start1 = LocalDateTime.of(2020, 1, 1, 0, 0),
        end1 = LocalDateTime.of(2021, 1, 1, 0, 0),
        start2 = LocalDateTime.of(2021, 1, 1, 0, 0),
        end2 = LocalDateTime.of(2022, 1, 1, 0, 0);
System.out.println(Period.between(start1.toLocalDate(), end1.toLocalDate()));
System.out.println(Duration.between(start1, end1).toDays());
System.out.println(Period.between(start2.toLocalDate(), end2.toLocalDate()));
System.out.println(Duration.between(start2, end2).toDays());
P1Y
366
P1Y
365
Anakhand
fuente
5

Hay algún problema para el código Tapas Bose y el código Thomas. Si la diferencia de tiempo es negativa, la matriz obtiene los valores negativos. Por ejemplo si

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);

devuelve 0 años 0 meses 1 días -1 horas 0 minutos 0 segundos.

Creo que la salida correcta es: 0 años 0 meses 0 días 23 horas 0 minutos 0 segundos.

Propongo separar las instancias LocalDateTime en las instancias LocalDate y LocalTime. Después de eso, podemos obtener las instancias de período y duración de Java 8. La instancia de Duración se separa en el número de días y el valor de tiempo a lo largo del día (<24 h) con la corrección posterior del valor del período. Cuando el segundo valor de LocalTime es anterior al primer valor de LocalTime, es necesario reducir el período de un día.

Aquí está mi manera de calcular la diferencia LocalDateTime:

private void getChronoUnitForSecondAfterFirst(LocalDateTime firstLocalDateTime, LocalDateTime secondLocalDateTime, long[] chronoUnits) {
    /*Separate LocaldateTime on LocalDate and LocalTime*/
    LocalDate firstLocalDate = firstLocalDateTime.toLocalDate();
    LocalTime firstLocalTime = firstLocalDateTime.toLocalTime();

    LocalDate secondLocalDate = secondLocalDateTime.toLocalDate();
    LocalTime secondLocalTime = secondLocalDateTime.toLocalTime();

    /*Calculate the time difference*/
    Duration duration = Duration.between(firstLocalDateTime, secondLocalDateTime);
    long durationDays = duration.toDays();
    Duration throughoutTheDayDuration = duration.minusDays(durationDays);
    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Duration is: " + duration + " this is " + durationDays
            + " days and " + throughoutTheDayDuration + " time.");

    Period period = Period.between(firstLocalDate, secondLocalDate);

    /*Correct the date difference*/
    if (secondLocalTime.isBefore(firstLocalTime)) {
        period = period.minusDays(1);
        Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
                "minus 1 day");
    }

    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Period between " + firstLocalDateTime + " and "
            + secondLocalDateTime + " is: " + period + " and duration is: "
            + throughoutTheDayDuration
            + "\n-----------------------------------------------------------------");

    /*Calculate chrono unit values and  write it in array*/
    chronoUnits[0] = period.getYears();
    chronoUnits[1] = period.getMonths();
    chronoUnits[2] = period.getDays();
    chronoUnits[3] = throughoutTheDayDuration.toHours();
    chronoUnits[4] = throughoutTheDayDuration.toMinutes() % 60;
    chronoUnits[5] = throughoutTheDayDuration.getSeconds() % 60;
}

El método anterior se puede usar para calcular la diferencia de cualquier valor de fecha y hora local, por ejemplo:

public long[] getChronoUnits(String firstLocalDateTimeString, String secondLocalDateTimeString) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    LocalDateTime firstLocalDateTime = LocalDateTime.parse(firstLocalDateTimeString, formatter);
    LocalDateTime secondLocalDateTime = LocalDateTime.parse(secondLocalDateTimeString, formatter);

    long[] chronoUnits = new long[6];
    if (secondLocalDateTime.isAfter(firstLocalDateTime)) {
        getChronoUnitForSecondAfterFirst(firstLocalDateTime, secondLocalDateTime, chronoUnits);
    } else {
        getChronoUnitForSecondAfterFirst(secondLocalDateTime, firstLocalDateTime, chronoUnits);
    }
    return chronoUnits;
}

Es conveniente escribir una prueba unitaria para el método anterior (ambos son miembros de la clase PeriodDuration). Aquí está el código:

@RunWith(Parameterized.class)
public class PeriodDurationTest {

private final String firstLocalDateTimeString;
private final String secondLocalDateTimeString;
private final long[] chronoUnits;

public PeriodDurationTest(String firstLocalDateTimeString, String secondLocalDateTimeString, long[] chronoUnits) {
    this.firstLocalDateTimeString = firstLocalDateTimeString;
    this.secondLocalDateTimeString = secondLocalDateTimeString;
    this.chronoUnits = chronoUnits;
}

@Parameters
public static Collection<Object[]> periodValues() {
    long[] chronoUnits0 = {0, 0, 0, 0, 0, 0};
    long[] chronoUnits1 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits2 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits3 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits4 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits5 = {0, 0, 1, 23, 0, 0};
    long[] chronoUnits6 = {29, 8, 24, 12, 0, 50};
    long[] chronoUnits7 = {29, 8, 24, 12, 0, 50};
    return Arrays.asList(new Object[][]{
        {"2015-09-09 21:46:44", "2015-09-09 21:46:44", chronoUnits0},
        {"2015-09-09 21:46:44", "2015-09-09 22:46:44", chronoUnits1},
        {"2015-09-09 21:46:44", "2015-09-10 20:46:44", chronoUnits2},
        {"2015-09-09 21:46:44", "2015-09-09 20:46:44", chronoUnits3},
        {"2015-09-10 20:46:44", "2015-09-09 21:46:44", chronoUnits4},
        {"2015-09-11 20:46:44", "2015-09-09 21:46:44", chronoUnits5},
        {"1984-12-16 07:45:55", "2014-09-09 19:46:45", chronoUnits6},
        {"2014-09-09 19:46:45", "1984-12-16 07:45:55", chronoUnits6}
    });
}

@Test
public void testGetChronoUnits() {
    PeriodDuration instance = new PeriodDuration();
    long[] expResult = this.chronoUnits;
    long[] result = instance.getChronoUnits(this.firstLocalDateTimeString, this.secondLocalDateTimeString);
    assertArrayEquals(expResult, result);
}

}

Todas las pruebas tienen éxito independientemente de si el valor del primer LocalDateTime es anterior y para cualquier valor de LocalTime.

Gennady Kolomoets
fuente
No puedo reproducir su afirmación de que el código de Thomas usando su entrada anterior produce signos mixtos. Mi salida es: "0 años 0 meses 0 días 23 horas 0 minutos 0 segundos". Y lo he probado justo ahora.
Meno Hochschild
Gracias por el comentario. Probé a fondo el código de Thomas, de hecho, ¡funciona correctamente! La magia se realiza por LocalDateTime hasta el método de corrección de unidades crono. Los valores negativos en el código de Thomas aparecen si el primer DateTime es posterior al segundo. Pero esto se puede corregir fácilmente, por ejemplo, como hice en el código anterior. Gracias de nuevo.
Gennady Kolomoets
Bueno, el código de Thomas y mi biblioteca Time4J que usan el mismo algoritmo para el cálculo de duraciones pueden producir signos negativos, pero solo durante toda la duración. Ese es el punto crucial! El signo se relaciona con la duración completa y, por lo tanto, describe si el inicio es posterior al final y nunca está relacionado con componentes de duración única. Los signos mixtos no son posibles aquí y evitarían tal interpretación de inicio en relación con el final (el ejemplo contrario es Joda-Time-period o java.time.Perioddonde los usuarios pueden hacer cumplir / producir tales signos mixtos debido a un diseño interno diferente).
Meno Hochschild
5

Y la versión de @Thomas en Groovy con toma las unidades deseadas en una lista en lugar de codificar los valores. Esta implementación (que puede portarse fácilmente a Java, hice explícita la declaración de la función) hace que el enfoque de Thomas sea más reutilizable.

def fromDateTime = LocalDateTime.of(1968, 6, 14, 0, 13, 0)
def toDateTime = LocalDateTime.now()
def listOfUnits = [
    ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS,
    ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS,
    ChronoUnit.MILLIS]

println calcDurationInTextualForm(listOfUnits, fromDateTime, toDateTime)    

String calcDurationInTextualForm(List<ChronoUnit> listOfUnits, LocalDateTime ts, LocalDateTime to)
{
    def result = []

    listOfUnits.each { chronoUnit ->
        long amount = ts.until(to, chronoUnit)
        ts = ts.plus(amount, chronoUnit)

        if (amount) {
            result << "$amount ${chronoUnit.toString()}"
        }
    }

    result.join(', ')
}

Al momento de escribir esto, el código anterior regresa 47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis. Y, para la entrada de @Gennady Kolomoets, el código vuelve 23 Hours.

Cuando proporciona una lista de unidades, debe ordenarse por tamaño de las unidades (la más grande primero):

def listOfUnits = [ChronoUnit.WEEKS, ChronoUnit.DAYS, ChronoUnit.HOURS]
// returns 2495 Weeks, 3 Days, 8 Hours
ChrLipp
fuente
4

Aquí hay una respuesta muy simple a su pregunta. Funciona.

import java.time.*;
import java.util.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class MyClass {
public static void main(String args[]) {
    DateTimeFormatter T = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
    Scanner h = new Scanner(System.in);

    System.out.print("Enter date of birth[dd/mm/yyyy hh:mm]: ");
    String b = h.nextLine();

    LocalDateTime bd = LocalDateTime.parse(b,T);
    LocalDateTime cd = LocalDateTime.now();

    long minutes = ChronoUnit.MINUTES.between(bd, cd);
    long hours = ChronoUnit.HOURS.between(bd, cd);

    System.out.print("Age is: "+hours+ " hours, or " +minutes+ " minutes old");
}
}
GuardadoBeau
fuente
1
Debo mencionar que esto no es exacto. Intenta con esto. Dice 1 minuto de diferencia. LocalDateTime bd = LocalDateTime.of (2019, 11, 26, 15, 03, 55); LocalDateTime cd = LocalDateTime.of (2019, 11, 26, 15, 04, 45);
Mark Amabile el
Entré en un horario anoche y conseguí Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old. No creo que esto sea lo que se deseaba.
Ole VV
@ OleV.V. Se solucionó ese problema
SavedBeau,
1

Joda-Time

Como muchas de las respuestas requerían compatibilidad con API 26 y mi API mínima era 23, lo resolví con el siguiente código:

import org.joda.time.Days

LocalDate startDate = Something
LocalDate endDate = Something
// The difference would be exclusive of both dates, 
// so in most of use cases we may need to increment it by 1
Days.daysBetween(startDate, endDate).days
Kushal
fuente
1
El proyecto Joda-Time está en modo de mantenimiento, ya que su creador Stephen Colebourne creó las clases java.time definidas en JSR 310. La mayor parte de la funcionalidad java.time se transfiere a Java 6 y 7 en ThreeTen- Proyecto de backport . Más adaptado para Android temprano en el proyecto ThreeTenABP .
Basil Bourque
1

Después de más de cinco años respondo mi pregunta. Creo que el problema con una duración negativa se puede resolver con una simple corrección:

LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);

Period period = Period.between(fromDateTime.toLocalDate(), toDateTime.toLocalDate());
Duration duration = Duration.between(fromDateTime.toLocalTime(), toDateTime.toLocalTime());

if (duration.isNegative()) {
    period = period.minusDays(1);
    duration = duration.plusDays(1);
}
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);
long time[] = {hours, minutes, secs};
System.out.println(period.getYears() + " years "
            + period.getMonths() + " months "
            + period.getDays() + " days "
            + time[0] + " hours "
            + time[1] + " minutes "
            + time[2] + " seconds.");

Nota: El sitio https://www.epochconverter.com/date-difference ahora calcula correctamente la diferencia horaria.

Gracias a todos por su discusión y sugerencias.

Gennady Kolomoets
fuente
Gracias por la respuesta. Para las horas y más pequeños se pueden beneficiar de la toHours, toMinutesy toSecondslos métodos de Duration. Desde Java 9 aún más desde toMinutesPart()y toSecondsPart(). Y no veo el punto de envolver las horas, minutos y segundos en una matriz solo para eliminarlos nuevamente. En general, una buena respuesta, sin embargo.
Ole VV
Después de más de cinco años respondo mi pregunta. La pregunta se publicó desde una cuenta con un nombre, título y ubicación diferentes, ¿no parece haber mucho parecido? No es que tenga ninguna importancia, solo me pregunto.
Ole VV
"Después de más de cinco años respondo a mi pregunta" Supongo que era el OP :)
Tapas Bose