Java 8: differenza tra due LocalDateTime in più unità


266

Sto cercando di calcolare la differenza tra due LocalDateTime.

L'output deve essere del formato y years m months d days h hours m minutes s seconds. Ecco cosa ho scritto:

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

L'output che sto ottenendo è 29 years 8 months 24 days 12 hours 0 minutes 50 seconds. Ho controllato il mio risultato da questo sito Web (con valori 12/16/1984 07:45:55e 09/09/2014 19:46:45). La seguente schermata mostra l'output:

Convertitore di epoca

Sono abbastanza sicuro che i campi dopo il valore del mese vengono errati dal mio codice. Qualsiasi suggerimento sarebbe molto utile.

Aggiornare

Ho testato il mio risultato da un altro sito Web e il risultato ottenuto è diverso. Eccolo: calcola la durata tra due date (risultato: 29 anni, 8 mesi, 24 giorni, 12 ore, 0 minuti e 50 secondi).

Aggiornare

Dato che ho ottenuto due risultati diversi da due siti diversi, mi chiedo se l'algoritmo del mio calcolo sia legittimo o meno. Se uso i seguenti due LocalDateTimeoggetti:

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

Quindi l'output sta arrivando: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.

Da questo link dovrebbe essere 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds. Quindi l'algoritmo deve gestire anche i numeri negativi.

Nota che la domanda non riguarda quale sito mi ha dato quale risultato, ho bisogno di sapere l'algoritmo giusto e ho bisogno di avere i risultati giusti.


Solo un'ipotesi, ma potrebbe Period.between()applicare un arrotondamento?
Thomas,

3
Ho appena guardato il codice ancora una volta e sembra che il sito Web sia sbagliato (prova a calcolare te stesso). Se ometti la data, ovvero le differenze di anno, mese e giorno, otterrai l'ora di inizio 7:45:55e l'ora di fine 19:46:45(o 7:46:45PM). Quindi la differenza tra queste due volte è di 12 ore, 0 minuti e 50 secondi e mai 23 ore, 34 minuti e 12 secondi. Quindi il tuo calcolo attuale sembra essere corretto, almeno sulla parte temporale.
Thomas,

1
Fenomeno interessante su quel sito Web: aggiungi 10 anni alla data di inizio e la differenza di ore cambia da 23 a 8 - sicuramente un segno di bug.
Thomas,

8
Si noti che poiché LocalDateTimenon ha un fuso orario, potrebbe non esserci una risposta unica. Anche se si presume che i fusi orari di inizio e fine siano gli stessi, in alcune zone date come il 09-09-2014 saranno in Ora legale o in ora legale e in altre no. Questo potrebbe far cadere le cose di un'ora. Quindi calcolare la differenza con il secondo non ha senso a meno che non sia risolto.
Stuart Marks,

2
Capisci che l'utilizzo LocalDateTimeproduce risultati non realistici, dal momento che quella classe è intenzionalmente priva di qualsiasi concetto di fuso orario o offset da UTC? Per valori realistici, assegnare un fuso orario tramite ZoneIdper l'uso ZonedDateTime.
Basil Bourque,

Risposte:


163

Sfortunatamente, non sembra esserci una classe del periodo che copra anche il tempo, quindi potresti dover fare i calcoli da solo.

Fortunatamente, le classi di data e ora hanno molti metodi di utilità che lo semplificano in una certa misura. Ecco un modo per calcolare la differenza anche se non necessariamente il più veloce:

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.

L'idea di base è questa: creare una data di inizio temporanea e portare alla fine gli anni interi. Quindi regola tale data in base al numero di anni in modo che la data di inizio sia inferiore a un anno dalla fine. Ripeti l'operazione per ogni unità di tempo in ordine decrescente.

Finalmente un disclaimer : non ho preso in considerazione diversi fusi orari (entrambe le date dovrebbero essere nello stesso fuso orario) e non ho nemmeno testato / verificato come l'ora legale o altre modifiche in un calendario (come il fuso orario cambia in Samoa) influenza questo calcolo. Quindi usa con cura.


1
Hai la stessa idea di base, quindi il mio voto, ma per favore prova a usare lo stesso input, altrimenti il ​​diverso risultato è confuso.
Meno Hochschild,

@MenoHochschild è lo stesso input, appena preso dall'aggiornamento in cui l'OP ha problemi con tempi negativi. ;)
Thomas,

1
Buon algoritmo, ma tipo sbagliato (vedi disclaimer di Thomas). Prima di eseguire il calcolo, è necessario convertire le variabili LocalDateTime in ZonedDateTime utilizzando ad esempio il fuso orario predefinito (o qualsiasi fuso orario necessario): ZonedDateTime fromZonedDateTime = fromDateTime.atZone (ZoneId.systemDefault ());
Tristan,

2
@Thomas Il tuo esempio sta usando anche Java 8 - e la domanda è taggata come java-8. In effetti il ​​tuo esempio sta persino usando ChronoUnit:) ma facendo il lavoro "a mano".
Eugene Beresovsky,

3
@EugeneBeresovsky oh sì, hai ragione. Totalmente perso quello;) - Oltre a ciò, dovresti comunque sottrarre le unità più grandi dall'intervallo poiché ad esempio long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);restituirebbe un numero maggiore di 59 per qualsiasi intervallo di almeno 1 ora - e non è quello che l'OP vuole. Tenendo conto di ciò, non saresti in grado di effettuare solo 6 chiamate ChronoUnit#between()ed essere fatto.
Thomas

503

Ho trovato il modo migliore per farlo è con ChronoUnit.

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

Ulteriore documentazione è qui: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html


8
Non vedo un vero miglioramento. Rispetto risposta accettato Thomas' Basta sostituire tempDateTime.until( toDateTime, ChronoUnit.YEARS)con ChronoUnit.YEARS.between(fromDate, toDate). Ma le importanti righe aggiuntive come tempDateTime.plusYears( years )ecc. Mancano completamente nella tua risposta, quindi non aiuta l'OP. L'algoritmo completo conta!
Meno Hochschild,

9
Mi piace di più perché è più conciso e più leggibile. Questo è il modo migliore per trovare la differenza tra due date.
Somaiah Kumbera,

7
@SomaiahKumbera No, ti manca completamente il punto critico. L'OP non vuole una durata in una sola unità ma in più unità , e quindi questa risposta non è affatto una vera risposta. La preoccupazione del PO semplicemente non viene affrontata. Sii così gentile da rileggere la domanda. (Molti utenti sembrano aver frainteso la domanda).
Meno Hochschild,

126
@MenoHochschild, penso che in realtà tu manchi il punto critico. L'OP ha ricevuto la sua risposta più di un anno fa. Le 36 mila persone che stanno visualizzando questa domanda non si preoccupano della domanda specifica del PO. Sono stati guidati qui da Google e la mia risposta ha fornito loro quello che stavano cercando: una soluzione pulita e semplice per ottenere la differenza tra due date.
satnam,

10
Avevo bisogno della differenza di secondi tra due orari e ho iniziato a implementare la mia soluzione. In breve sembra complesso e ho preso su Google. La risposta di Satnam potrebbe non rispondere alla domanda OP ma sicuramente mi ha aiutato molto e scommetto che molti altri come me.
Julian,

43

Ecco un singolo esempio che utilizza Duration e TimeUnit per ottenere il 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)));

2
In realtà è possibile farlo in questo modo: String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());. I metodi della parte forniscono i numeri giusti per costruire una stringa. Penso che sia più leggibile.
Daantie,

Nota a margine del mio commento precedente: i metodi della parte sono disponibili solo da JDK 9 e versioni successive.
Daantie

40

Dovrebbe essere più semplice!

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

1
Credo che questa sia in realtà la soluzione semanticamente corretta a partire da Java 8. E prima di quella versione, JodaTime fa lo stesso.
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());

e poi utilizzare i metodi period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart().


Risposta estesa

Risponderò alla domanda originale, ovvero come ottenere la differenza di tempo tra due LocalDateTimesin anni, mesi, giorni, ore e minuti, in modo tale che la "somma" (vedi nota sotto) di tutti i valori per le diverse unità sia uguale al totale differenza temporale e tale che il valore di ciascuna unità è inferiore alla successiva unità più grande, cioè minutes < 60,hours < 24 e così via.

Dato due LocalDateTimes starte end, ad es

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

possiamo rappresentare il periodo assoluto tra i due con un — Durationforse usando Duration.between(start, end). Ma l'unità più grande che possiamo estrarre da a Durationè giorni (come unità temporale equivalente a 24 ore): vedi la nota sotto per una spiegazione. Per usare unità più grandi (mesi, anni) possiamo rappresentarlo Durationcon una coppia di ( Period, Duration), dove Periodmisura la differenza fino a una precisione di giorni e Durationrappresenta il 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());

Ora possiamo semplicemente usare i metodi definiti Perioded Durationestrarre le singole unità:

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

oppure, utilizzando il formato predefinito:

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

Nota su anni, mesi e giorni

Si noti che, nel java.timeconcetto, "unità" come "mese" o "anno" non rappresentano un valore temporale assoluto fisso, ma dipendono dalla data e dal calendario, come illustrato nell'esempio seguente:

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

5

C'è qualche problema con il codice Tapas Bose e il codice Thomas. Se la differenza di tempo è negativa, l'array ottiene i valori negativi. Ad esempio se

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

restituisce 0 anni 0 mesi 1 giorni -1 ore 0 minuti 0 secondi.

Penso che l'uscita giusta sia: 0 anni 0 mesi 0 giorni 23 ore 0 minuti 0 secondi.

Propongo di separare le istanze LocalDateTime sulle istanze LocalDate e LocalTime. Successivamente, è possibile ottenere le istanze Periodo e Durata Java 8. L'istanza Duration è separata per il numero di giorni e per il valore dell'intera giornata (<24h) con successiva correzione del valore del periodo. Quando il secondo valore LocalTime è precedente al valore firstLocalTime, è necessario ridurre il periodo di un giorno.

Ecco il mio modo per calcolare la differenza 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;
}

Il metodo sopra può essere utilizzato per calcolare la differenza di qualsiasi valore locale di data e ora, ad esempio:

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

È conveniente scrivere un test unitario per il metodo sopra (entrambi sono membri della classe PeriodDuration). Ecco il codice:

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

}

Tutti i test hanno esito positivo indipendentemente dal fatto che il valore del primo LocalDateTime sia precedente e per qualsiasi valore LocalTime.


Non riesco a riprodurre la tua affermazione che il codice Thomas usando il tuo input sopra produce segni misti. La mia uscita è: "0 anni 0 mesi 0 giorni 23 ore 0 minuti 0 secondi.". E ho testato proprio ora.
Meno Hochschild,

Grazie per il commento. Ho testato a fondo il codice Thomas, anzi, funziona correttamente! La magia viene eseguita da LocalDateTime fino a quando il metodo corregge le unità crono. I valori negativi nel codice Thomas vengono visualizzati se il primo DateTime è successivo al secondo. Ma questo può essere facilmente corretto, ad esempio, come ho fatto nel codice sopra. Grazie ancora.
Gennady Kolomoets,

Bene, il codice Thomas e la mia libreria Time4J che usano lo stesso algoritmo per il calcolo delle durate possono produrre segni negativi ma solo per l'intera durata. Questo è il punto cruciale! Il segno si riferisce all'intera durata e quindi descrive se l'inizio è successivo alla fine e non è mai correlato a singoli componenti di durata. I segni misti non sono possibili qui e impedirebbero tale interpretazione di inizio rispetto alla fine (il contro esempio è il periodo Joda o in java.time.Periodcui gli utenti possono applicare / produrre tali segni misti a causa del diverso design interno).
Meno Hochschild,

5

E la versione di @Thomas in Groovy con prende le unità desiderate in un elenco invece di codificare i valori. Questa implementazione (che può essere facilmente trasferita su Java - ho reso esplicita la dichiarazione di funzione) rende l'approccio di Thomas più riutilizzabile.

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 della stesura di questo documento, il codice sopra riportato ritorna 47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis. E, per l'input di @Gennady Kolomoets, il codice ritorna 23 Hours.

Quando si fornisce un elenco di unità, è necessario ordinarle in base alla dimensione delle unità (prima la più grande):

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

4

Ecco una risposta molto semplice alla tua domanda. Funziona.

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");
}
}

1
Devo dire che questo non è accurato. prova con questo. dice 1 minuto di differenza. LocalDateTime bd = LocalDateTime.of (2019, 11, 26, 15, 03, 55); LocalDateTime cd = LocalDateTime.of (2019, 11, 26, 15, 04, 45);
Mark Amabile,

Sono entrato un'ora la notte scorsa e ho ottenuto Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old. Non credo sia questo ciò che desideravamo.
Ole VV,

@ OleV.V. Risolto il problema
SavedBeau

1

Joda-Time

Poiché molte delle risposte richiedevano il supporto dell'API 26 e la mia API minima era 23, l'ho risolto con il codice seguente:

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

1
Il progetto Joda-Time è in modalità manutenzione, il suo creatore Stephen Colebourne ha continuato a creare le classi java.time definite in JSR 310. La maggior parte della funzionalità java.time è trasferita su Java 6 e 7 in ThreeTen- Progetto di backport . Ulteriore adattamento per Android iniziale nel progetto ThreeTenABP .
Basil Bourque,

1

Dopo più di cinque anni rispondo alla mia domanda. Penso che il problema con una durata negativa possa essere risolto con una semplice correzione:

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: il sito https://www.epochconverter.com/date-difference ora calcola correttamente la differenza oraria.

Grazie a tutti per la discussione e i suggerimenti.


Grazie per la risposta. Per le ore e più piccoli si può beneficiare della toHours, toMinutese toSecondsmetodi di Duration. Da Java 9 ancora di più da toMinutesPart()e toSecondsPart(). E non vedo il punto nel racchiudere ore, minuti e secondi in un array solo per eliminarli di nuovo. Generalmente una buona risposta, però.
Ole VV

Dopo più di cinque anni rispondo alla mia domanda. La domanda è stata posta da un account con un nome, titolo e posizione diversi, non sembra molto simile? Non che abbia alcuna importanza, mi chiedo solo.
Ole VV,

"Dopo più di cinque anni rispondo alla mia domanda" Suppongo di essere stato il PO :)
Tapas Bose
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.