Calcolo della differenza tra due istanze di data Java


433

Sto usando la java.util.Dateclasse Java in Scala e voglio confrontare un Dateoggetto e l'ora corrente. So di poter calcolare il delta usando getTime ():

(new java.util.Date()).getTime() - oldDate.getTime()

Tuttavia, questo mi lascia solo con un longmillisecondo rappresentante. Esiste un modo più semplice e migliore per ottenere un delta temporale?


10
Perché nessun amore per il tempo Joda? È praticamente l'opzione migliore se hai intenzione di gestire le date in Java.
Doctor Jones,

7
Si prega di controllare la mia soluzione elegante 2 di linea, senza l'utilizzo di Joda e dando il risultato in qualsiasi TIMEUNIT a stackoverflow.com/a/10650881/82609
Sebastien Lorber

2
Peccato per tutti quelli che raccomandano il tempo Joda e non raccomandano una vera risposta Java ...
Zizouz212

2
@ Zizouz212 Per quanto riguarda la raccomandazione di Joda-Time, le vecchie classi di data e ora in bundle con Java sono cattive, veramente brutte, mal progettate, confuse e problematiche. Così male che Joda-Time ha avuto un enorme successo in sostituzione. Così male che anche Sun / Oracle si sono arresi e hanno adottato il pacchetto java.time come parte di Java 8 e versioni successive. Le lezioni di java.time sono ispirate a Joda-Time. Sia Joda-Time che java.time sono guidati dallo stesso uomo, Stephen Colbourne . Direi, “Vergogna su chiunque raccomandare l'uso di Date, Calendare SimpleDateFormat”.
Basil Bourque,

2
Mentre Joda Time è stata probabilmente una buona risposta quando è stata posta la domanda, oggi la migliore risposta per chiunque possa usare Java 8 è usare java.time.Periode / o Duration. Vedi la risposta di Basil Bourque di seguito .
Ole VV,

Risposte:


198

L' DateAPI JDK è purtroppo rotta in modo orribile. Consiglio di usare la libreria Joda Time .

Joda Time ha un concetto di intervallo di tempo :

Interval interval = new Interval(oldTime, new Instant());

EDIT: A proposito, Joda ha due concetti: Intervalper rappresentare un intervallo di tempo tra due istanti di tempo (rappresentano il tempo tra le 8 e le 10) e un Durationche rappresenta un periodo di tempo senza i limiti di tempo effettivi (ad esempio rappresentano due ore!)

Se ti interessano solo i confronti temporali, la maggior parte delle Dateimplementazioni (inclusa quella JDK) implementa l' Comparableinterfaccia che ti consente di utilizzare ilComparable.compareTo()


btw - vuoi dire Comparable.compareTo(), no Comparable.compare().
Scott Morrison,

Joda-Time ha tre classi per rappresentare un arco di tempo in vari modi: intervallo, durata e periodo. Questa risposta corretta discute i primi due. Vedi la mia risposta per informazioni sul Periodo.
Basil Bourque,

Java 8 ha una nuova data e ora api come joda.
martedì

11
Il nuovo java.timepacchetto in Java 8 è ispirato a Joda-Time ma non è un sostituto drop-in. Ognuno ha i suoi pro e contro. Fortunatamente non devi scegliere tra di loro. Usa ciascuno per i suoi punti di forza fintanto che stai attento con le tue importdichiarazioni. Vedi questa altra risposta per esempio di java.time.
Basil Bourque,

6
Cordiali saluti, il progetto Joda-Time è ora in modalità di manutenzione , con il team che consiglia la migrazione alle classi java.time . Vedi Tutorial di Oracle .
Basil Bourque,

550

Diff semplice (senza lib)

/**
 * Get a diff between two dates
 * @param date1 the oldest date
 * @param date2 the newest date
 * @param timeUnit the unit in which you want the diff
 * @return the diff value, in the provided unit
 */
public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
    long diffInMillies = date2.getTime() - date1.getTime();
    return timeUnit.convert(diffInMillies,TimeUnit.MILLISECONDS);
}

E poi puoi chiamare:

getDateDiff(date1,date2,TimeUnit.MINUTES);

per ottenere la differenza delle 2 date in minuti.

TimeUnitè java.util.concurrent.TimeUnitun enum Java standard che va dai nanos ai giorni.


Differenza leggibile dall'uomo (senza lib)

public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {

    long diffInMillies = date2.getTime() - date1.getTime();

    //create the list
    List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
    Collections.reverse(units);

    //create the result map of TimeUnit and difference
    Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
    long milliesRest = diffInMillies;

    for ( TimeUnit unit : units ) {

        //calculate difference in millisecond 
        long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
        long diffInMilliesForUnit = unit.toMillis(diff);
        milliesRest = milliesRest - diffInMilliesForUnit;

        //put the result in the map
        result.put(unit,diff);
    }

    return result;
}

http://ideone.com/5dXeu6

L'output è simile Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}, con le unità ordinate.

Devi solo convertire quella mappa in una stringa intuitiva.


avvertimento

Gli snippet di codice sopra calcolano una semplice differenza tra 2 istanti. Può causare problemi durante un cambio di ora legale, come spiegato in questo post . Questo significa che se calcoli la differenza tra le date senza tempo potresti avere un giorno / ora mancante.

A mio avviso, la data di diff è un po 'soggettiva, specialmente nei giorni. Potresti:

  • contare il numero di 24 ore di tempo trascorso: giorno + 1 - giorno = 1 giorno = 24 ore

  • contare il numero di tempo trascorso, occupandosi dell'ora legale: giorno + 1 - giorno = 1 = 24 ore (ma utilizzando l'ora di mezzanotte e l'ora legale potrebbe essere 0 giorni e 23 ore)

  • contare il numero di day switches, che significa giorno + 1 13:00 - giorno 11 = 1 giorno, anche se il tempo trascorso è di sole 2 ore (o 1 ora in caso di ora legale: p)

La mia risposta è valida se la tua definizione della data differisce nei giorni corrisponde al primo caso

Con JodaTime

Se stai usando JodaTime puoi ottenere il diff per 2 istanti (millies backed ReadableInstant) con:

Interval interval = new Interval(oldInstant, new Instant());

Ma puoi anche ottenere il diff per date / orari locali:

// returns 4 because of the leap year of 366 days
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5), PeriodType.years()).getYears() 

// this time it returns 5
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5+1), PeriodType.years()).getYears() 

// And you can also use these static methods
Years.yearsBetween(LocalDate.now(), LocalDate.now().plusDays(365*5)).getYears()

Wow, puoi davvero insegnare a un vecchio cane nuovi trucchi! Non ne avevo mai sentito parlare prima, molto utile per tradurre le differenze di data in stringhe significative.
Jeremy Goodell,

@SebastienLorber In TimeUnit esiste un modo per calcolare la differenza in questo modo? "La sveglia è impostata per 3 giorni, 4 ore e 12 minuti da adesso".
Mi piace il

cose geniali mi hanno davvero risparmiato un sacco di tempo. Apprezzo il tuo aiuto.
Lyju I Edwinson,

Ho perso 3 giorni della mia vita con Java Dates e l'ho buttato via e sostituito con questo. Grazie.
user1091524

Questa è la migliore risposta che ho visto da quando sono arrivato su StackOverflow! : D: D: D
Freddo

153
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

Nota che funziona con le date UTC, quindi la differenza potrebbe essere un giorno libero se guardi le date locali. E farlo funzionare correttamente con le date locali richiede un approccio completamente diverso a causa dell'ora legale.


6
Questo in realtà non funziona correttamente in Android. Esistono errori di arrotondamento. Esempio 19-21 maggio dice 1 giorno perché lancia 1,99 a 1. Usa il round prima di lanciare a int.
Pratik Mandrekar,

4
Questa è la risposta migliore e più semplice. Quando si calcola una differenza tra due date, i fusi orari locali si sottraggono a vicenda ... in modo che la risposta corretta (come doppia) sia data semplicemente da ((doppia) (newer.getTime () - older.getTime ()) / (86400.0 * 1000.0); ... come doppio, hai anche il giorno frazionario che può essere facilmente convertito in HH: MM: ss.
scottb,

8
@scottb: il problema con le date locali è che puoi avere l'ora legale, il che significa che alcuni giorni hanno 23 o 25 ore, potenzialmente incasinando il risultato.
Michael Borgwardt,

1
@Steve: sono 28 per me quando li definisco come questa nuova Data (115, 2, 26); (presta attenzione al documento API per i parametri). È possibile che tu li stia analizzando utilizzando il formato data degli Stati Uniti e in modalità clemente, in modo che il 26/03/2015 sia interpretato come il 3 ° giorno del 26 ° mese del 2015?
Michael Borgwardt,

1
@Steve: hm, non sono sicuro del motivo per cui ho ottenuto un risultato diverso prima, ma ora posso riprodurre il tuo errore. Le parentesi graffe nel tuo codice sono diverse rispetto alla mia risposta, che provoca il (endDate.getTime() - startDate.getTime())cast intinvece del risultato finale e stai ottenendo un overflow di numeri interi.
Michael Borgwardt,

54

Utilizzando il framework java.time incorporato in Java 8+:

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println("ISO-8601: " + duration);
System.out.println("Minutes: " + duration.toMinutes());

Produzione:

ISO-8601: PT24H10M

Minuti: 1450

Per ulteriori informazioni, consultare Oracle Tutorial e lo standard ISO 8601 .


5
Questo, o utilizzare Periodinvece che Durationper le date.
Aphex,

53

È necessario definire il problema in modo più chiaro. Si può solo prendere il numero di millisecondi tra i due Dateoggetti e dividere per il numero di millisecondi in 24 ore, per esempio ... ma:

  • Questo non prenderà in considerazione i fusi orari - Dateè sempre in UTC
  • Questo non prenderà in considerazione l'ora legale (dove possono esserci giorni che durano solo 23 ore, per esempio)
  • Anche in UTC, quanti giorni ci sono dal 16 agosto alle 18:00 fino al 18 agosto? Sono solo 27 ore, quindi significa un giorno? O dovrebbe essere di tre giorni perché copre tre date?

1
Ho pensato java.util. La data era solo un piccolo involucro attorno a una rappresentazione time-millis, interpretata nel fuso orario locale (predefinito). Stampare una data mi dà una rappresentazione del fuso orario locale. Sono confuso qui?
Adriaan Koster,

46

tl; dr

Converti i tuoi obsoleti java.util.Dategli oggetti per la loro sostituzione, java.time.Instant. Quindi calcolare il tempo trascorso come a Duration.

Duration d = 
    Duration.between(                   // Calculate the span of time between two moments as a number of hours, minutes, and seconds.
        myJavaUtilDate.toInstant() ,    // Convert legacy class to modern class by calling new method added to the old class.
        Instant.now()                   // Capture the current moment in UTC. About two and a half hours later in this example.
    )
;

d.toString (): PT2H34M56S

d.toMinutes (): 154

d.toMinutesPart (): 34

Formato ISO 8601: PnYnMnDTnHnMnS

Lo standard sensibile ISO 8601 definisce una concisa rappresentazione testuale di un arco di tempo come un numero di anni, mesi, giorni, ore, ecc. Lo standard chiama tale intervallo di tempo . Il formato è PnYnMnDTnHnMnSdove il P"Periodo" significa, Tsepara la porzione di data dalla porzione di tempo, e in mezzo ci sono numeri seguiti da una lettera.

Esempi:

  • P3Y6M4DT12H30M5S
    tre anni, sei mesi, quattro giorni, dodici ore, trenta minuti e cinque secondi
  • PT4H30M
    Quattro ore e mezza

java.time

Il framework java.time incorporato in Java 8 e successivamente soppianta le vecchie java.util.Date/ java.util.Calendarclassi problematiche . Le nuove classi si ispirano al framework Joda-Time di grande successo , inteso come suo successore, simile nel concetto ma riprogettato. Definito da JSR 310 . Esteso dal progetto ThreeTen-Extra . Vedi il tutorial .

Momento

La Instantclasse rappresenta un momento sulla linea temporale in UTC con una risoluzione di nanosecondi (fino a nove (9) cifre di una frazione decimale).

Instant instant = Instant.now() ;  // Capture current moment in UTC.

Meglio evitare le classi legacy come Date/ Calendar. Ma se devi interagire con il vecchio codice non ancora aggiornato a java.time , converti avanti e indietro. Chiama nuovi metodi di conversione aggiunti alle vecchie classi. Per passare da un java.util.Datea un Instant, chiama Date::toInstant.

Instant instant = myJavaUtilDate.toInstant() ;  // Convert from legacy `java.util.Date` class to modern `java.time.Instant` class.

Lasso di tempo

Le classi java.time hanno diviso questa idea di rappresentare un arco di tempo come un numero di anni, mesi, giorni, ore, minuti, secondi in due metà:

  • Period per anni, mesi, giorni
  • Duration per giorni, ore, minuti, secondi

Ecco un esempio

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime future = now.plusMinutes ( 63 );
Duration duration = Duration.between ( now , future );

Scarica alla console.

Entrambi Periode Durationusano lo standard ISO 8601 per generare una rappresentazione String del loro valore.

System.out.println ( "now: " + now + " to future: " + now + " = " + duration );

ora: 2015-11-26T00: 46: 48.016-05: 00 [America / Montreal] per il futuro: 2015-11-26T00: 46: 48.016-05: 00 [America / Montreal] = PT1H3M

Java 9 aggiunge metodi per Durationottenere la parte dei giorni, la parte delle ore, la parte dei minuti e la parte dei secondi.

È possibile ottenere il numero totale di giorni o ore o minuti o secondi o millisecondi o nanosecondi nell'intera durata.

long totalHours = duration.toHours();

In Java 9 la Durationclasse ottiene nuovi metodi per restituire le varie parti di giorni, ore, minuti, secondi, millisecondi / nanosecondi. Chiamare i to…Partmetodi: toDaysPart(), toHoursPart(), e così via.

ChronoUnit

Se ti interessa solo una granularità del tempo più semplice, come ad esempio il "numero di giorni trascorsi", usa l' ChronoUnitenum.

long daysElapsed = ChronoUnit.DAYS.between( earlier , later );

Un altro esempio.

Instant now = Instant.now();
Instant later = now.plus( Duration.ofHours( 2 ) );

long minutesElapsed = ChronoUnit.MINUTES.between( now , later );

120


Informazioni su java.time

Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantare la vecchia fastidiosi legacy classi data-time come java.util.Date, Calendar, e SimpleDateFormat.

Il progetto Joda-Time , ora in modalità manutenzione , consiglia la migrazione a java.time.

Per saperne di più, consulta il tutorial Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .

Dove ottenere le classi java.time?

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un banco di prova per possibili aggiunte future a java.time. Si possono trovare alcune classi utili, come per esempio Interval, YearWeek, YearQuartere altro .


Joda-Time

AGGIORNAMENTO: il progetto Joda-Time è ora in modalità manutenzione , con il team che consiglia la migrazione alle classi java.time . Lascio questa sezione intatta per la storia.

La libreria Joda-Time utilizza ISO 8601 per i suoi valori predefiniti. La sua Periodclasse analizza e genera queste stringhe PnYnMnDTnHnMnS.

DateTime now = DateTime.now(); // Caveat: Ignoring the important issue of time zones.
Period period = new Period( now, now.plusHours( 4 ).plusMinutes( 30));
System.out.println( "period: " + period );

Renders:

period: PT4H30M

È divertente che tu abbia creato un muro di testo irrilevante con "tl; dr". La domanda non riguarda come ottenere il timestamp da X fa o in X unità di tempo, ma come ottenere il delta tra due date. Questo è tutto.
Buffalo,

@Buffalo Non capisco il tuo commento. La mia risposta coinvolge Period, Duratione ChronoUnit, tre classi il cui scopo è determinare il delta tra i punti del tempo. Indica quali parti del mio "muro di testo" sono irrilevanti. E non sei corretto nel dire che la Domanda ha richiesto un "delta tra le date": La Domanda ha richiesto un delta tra gli Dateoggetti, che sono momenti data-ora, non "date" nonostante lo sfortunato nome di quella classe.
Basil Bourque,

Non c'è nulla nel tuo commento che gestisca due oggetti java.util.Date esistenti. Ho provato a utilizzare vari frammenti nel mio codice e non ho trovato nulla che utilizza un oggetto java.util.Date.
Buffalo,

@Buffalo Abbastanza giusto, buone critiche. Ho aggiunto il codice nella sezione "tl; dr" convertendo da a java.util.Datea Instant(basta chiamare .toInstant). E ho aggiunto la Momentsezione per spiegare. Hai menzionato una coppia di Dateoggetti, ma in realtà la Domanda utilizza solo un singolo Dateoggetto esistente e quindi cattura il momento attuale, quindi ho fatto lo stesso. Grazie per il feedback! Suggerimento: rinuncia all'utilizzo Date: quelle classi legacy sono davvero un disastro terribile.
Basil Bourque,


23

Un'alternativa leggermente più semplice:

System.currentTimeMillis() - oldDate.getTime()

Per quanto riguarda "più bello": beh, di cosa hai bisogno esattamente? Il problema con la rappresentazione della durata di tempo come numero di ore e giorni ecc. È che può portare a inesattezze e aspettative errate a causa della complessità delle date (ad esempio, i giorni possono avere 23 o 25 ore a causa dell'ora legale).


22

L'uso di un approccio in millisecondi può causare problemi in alcune lingue.

Prendiamo, ad esempio, la differenza tra le due date 24/03/2007 e 25/03/2007 dovrebbe essere di 1 giorno;

Tuttavia, utilizzando il percorso in millisecondi, otterrai 0 giorni, se lo esegui nel Regno Unito!

/** Manual Method - YIELDS INCORRECT RESULTS - DO NOT USE**/  
/* This method is used to find the no of days between the given dates */  
public long calculateDays(Date dateEarly, Date dateLater) {  
   return (dateLater.getTime() - dateEarly.getTime()) / (24 * 60 * 60 * 1000);  
} 

Il modo migliore per implementare questo è usare java.util.Calendar

/** Using Calendar - THE CORRECT WAY**/  
public static long daysBetween(Calendar startDate, Calendar endDate) {  
  Calendar date = (Calendar) startDate.clone();  
  long daysBetween = 0;  
  while (date.before(endDate)) {  
    date.add(Calendar.DAY_OF_MONTH, 1);  
    daysBetween++;  
  }  
  return daysBetween;  
}  

19
Potresti per favore attribuire credito all'autore originale di questo codice e alla terza frase, il cui post sul blog risale al 2007 ?
mercoledì

Non è un po 'inefficace?
Gangnus,

Non funziona correttamente daysB Between (nuovo GregorianCalendar (2014,03,01), nuovo GregorianCalendar (2014,04,02))); restituisce 31 e dovrebbe restituire 32: timeanddate.com/date/…
marcolopes

5
@marcolopes - Ti sbagli - perché i mesi di calendario sono a base zero. Sono sicuro che intendi marzo / aprile, ma quello che stai testando è aprile / giugno, che è il 31. Per sicurezza, scrivilo come -> nuovo GregorianCalendar (2014, Calendar.MARCH, 1) ....
Zio Iroh,

@UncleIroh, hai ragione! Ho perso questo fatto importante (i mesi di calendario sono a base zero). Devo rivedere questa domanda di nuovo.
marcolopes,

22

Esistono molti modi per trovare la differenza tra date e orari. Uno dei modi più semplici che conosco sarebbe:

      Calendar calendar1 = Calendar.getInstance();
      Calendar calendar2 = Calendar.getInstance();
      calendar1.set(2012, 04, 02);
      calendar2.set(2012, 04, 04);
      long milsecs1= calendar1.getTimeInMillis();
      long milsecs2 = calendar2.getTimeInMillis();
      long diff = milsecs2 - milsecs1;
      long dsecs = diff / 1000;
      long dminutes = diff / (60 * 1000);
      long dhours = diff / (60 * 60 * 1000);
      long ddays = diff / (24 * 60 * 60 * 1000);

      System.out.println("Your Day Difference="+ddays);

L'istruzione print è solo un esempio: puoi formattarla come preferisci.


5
@ manoj kumar bardhan: benvenuto nello stack di overflow: come vedi la domanda e le risposte hanno anni. La tua risposta dovrebbe aggiungere più alla domanda / risposta di quelle esistenti.
Jayan,

3
Che dire dei giorni che hanno 23 o 25 ore a causa di una transizione DST?
Joni,

19

Dato che tutte le risposte qui sono corrette, ma uso java legacy o librerie di terze parti come joda o simili, lascerò perdere un altro modo usando le nuove classi java.time in Java 8 e versioni successive. Vedi Tutorial Oracle .

Usa LocalDatee ChronoUnit:

LocalDate d1 = LocalDate.of(2017, 5, 1);
LocalDate d2 = LocalDate.of(2017, 5, 18);

long days = ChronoUnit.DAYS.between(d1, d2);
System.out.println( days );

9

Sottraendo le date in millisecondi opere (come descritto in un altro post), ma si hanno di utilizzare HOUR_OF_DAY e non ora in cui eliminare le parti temporali le date:

public static final long MSPERDAY = 60 * 60 * 24 * 1000;
...
final Calendar dateStartCal = Calendar.getInstance();
dateStartCal.setTime(dateStart);
dateStartCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateStartCal.set(Calendar.MINUTE, 0);
dateStartCal.set(Calendar.SECOND, 0);
dateStartCal.set(Calendar.MILLISECOND, 0);
final Calendar dateEndCal = Calendar.getInstance();
dateEndCal.setTime(dateEnd);
dateEndCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateEndCal.set(Calendar.MINUTE, 0);
dateEndCal.set(Calendar.SECOND, 0);
dateEndCal.set(Calendar.MILLISECOND, 0);
final long dateDifferenceInDays = ( dateStartCal.getTimeInMillis()
                                  - dateEndCal.getTimeInMillis()
                                  ) / MSPERDAY;
if (dateDifferenceInDays > 15) {
    // Do something if difference > 15 days
}

1
Questo è il metodo migliore per determinare la differenza tra due date del calendario, senza uscire dalle librerie standard. La maggior parte delle altre risposte considera un giorno come un periodo arbitrario di 24 ore. Se si dovessero sottrarre secondi saltanti anziché aggiungerli, il calcolo finale potrebbe essere disattivato di uno a causa del troncamento, poiché la differenza assoluta potrebbe essere leggermente inferiore a un numero intero di multipli di MSPERDAY.
JulianSymes,

8

Se non vuoi usare JodaTime o simili, la soluzione migliore è probabilmente questa:

final static long MILLIS_PER_DAY = 24 * 3600 * 1000;
long msDiff= date1.getTime() - date2.getTime();
long daysDiff = Math.round(msDiff / ((double)MILLIS_PER_DAY));

Il numero di ms al giorno non è sempre lo stesso (a causa dell'ora legale e dei secondi bisestili), ma è molto vicino e almeno le deviazioni dovute all'ora legale si annullano per periodi più lunghi. Pertanto la divisione e l'arrotondamento daranno un risultato corretto (almeno fino a quando il calendario locale utilizzato non contiene strani salti di tempo diversi dall'ora legale e dai secondi da saltare).

Si noti che questo presuppone ancora che date1e date2siano impostati alla stessa ora del giorno. Per le diverse ore del giorno, dovresti prima definire cosa significa "differenza di data", come sottolineato da Jon Skeet.


La questione è in date1.getTime()contro date2.getTime(). Pertanto, la differenza tra il 03-03-2016 e il 31-03-2016 calcolerà 27 giorni mentre tu vorresti 28 giorni.
Malat,

@malat: mi dispiace, non posso seguirlo. L'ho appena provato - diffendo dal 03-03-2016 al 31-03-2016 con il mio codice calcola 28 giorni. Se calcola qualcos'altro nel tuo esempio, considera di fare una domanda separata.
sleske,

Inoltre, hai letto il mio avvertimento? "questo presuppone ancora che date1 e date2 siano impostati alla stessa ora del giorno". Hai forse usato diverse ore del giorno nel tuo test?
sleske,

Ah giusto ! Mi mancava il trucco Math.round(), che sembra sicuro nei calendari del "mondo reale". Scusa per il rumore.
Malat,

8

Dai un'occhiata a Joda Time , che è un'API Date / Time migliorata per Java e dovrebbe funzionare bene con Scala.


sostituito da java.time (JSR-310) in Java 8
malat

5

Vorrei mostrare la differenza tra Joda Interval e Days:

DateTime start = new DateTime(2012, 2, 6, 10, 44, 51, 0);
DateTime end = new DateTime(2012, 2, 6, 11, 39, 47, 1);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();
System.out.println(period.getYears() + " years, " + period.getMonths() + " months, " + period.getWeeks() + " weeks, " + period.getDays() + " days");
System.out.println(period.getHours() + " hours, " + period.getMinutes() + " minutes, " + period.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *1 weeks, 1 days*
//0 hours, 54 minutes, 56 seconds 

//Period can set PeriodType,such as PeriodType.yearMonthDay(),PeriodType.yearDayTime()...
Period p = new Period(start, end, PeriodType.yearMonthDayTime());
System.out.println(p.getYears() + " years, " + p.getMonths() + " months, " + p.getWeeks() + " weeks, " + p.getDays() + "days");
System.out.println(p.getHours() + " hours, " + p.getMinutes() + " minutes, " + p.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *0 weeks, 8 days*
//0 hours, 54 minutes, 56 seconds 

5

Se hai bisogno di una stringa di ritorno formattata come "2 giorni 03h 42m 07s", prova questo:

public String fill2(int value)
{
    String ret = String.valueOf(value);

    if (ret.length() < 2)
        ret = "0" + ret;            
    return ret;
}

public String get_duration(Date date1, Date date2)
{                   
    TimeUnit timeUnit = TimeUnit.SECONDS;

    long diffInMilli = date2.getTime() - date1.getTime();
    long s = timeUnit.convert(diffInMilli, TimeUnit.MILLISECONDS);

    long days = s / (24 * 60 * 60);
    long rest = s - (days * 24 * 60 * 60);
    long hrs = rest / (60 * 60);
    long rest1 = rest - (hrs * 60 * 60);
    long min = rest1 / 60;      
    long sec = s % 60;

    String dates = "";
    if (days > 0) dates = days + " Days ";

    dates += fill2((int) hrs) + "h ";
    dates += fill2((int) min) + "m ";
    dates += fill2((int) sec) + "s ";

    return dates;
}

2
Whoa, perché lanciare il tuo quando Joda-Time fornisce la classe Period già scritta e sottoposta a debug?
Basil Bourque,

8
Perché dovrei scaricare una libreria con un FileSize compresso di 4,1 MB e aggiungerlo al mio progetto, quando ho bisogno solo di 32 righe di codice ???
Ingo,

1
Perché Joda-Time è come le patatine: non puoi mangiarne solo una. Utilizzerai Joda-Time dappertutto. E poiché Joda-Time è un codice ben collaudato e logoro. E poiché Joda-Time analizza e genera stringhe di durata ISO 8601 standard che possono essere utili per serializzare o riportare questi valori. E poiché Joda-Time include formattatori per stampare rappresentazioni localizzate di questi valori.
Basil Bourque,

Non tutto il tuo codice è testato. stdsopra non è definito.
Basil Bourque,

@Basil Bourque: Grazie per il suggerimento. Ho corretto la fonte. Questo errore è venuto dalla traduzione in inglese.
Ingo,

5

Nota: startDate e endDates sono -> java.util.Date

import org.joda.time.Duration;
import org.joda.time.Interval;
// Use .getTime() unless it is a joda DateTime object
Interval interval = new Interval(startDate.getTime(), endDate.getTime());
Duration period = interval.toDuration();
//gives the number of days elapsed between start 
period.getStandardDays();

e data di fine

Simile ai giorni, puoi anche ottenere ore, minuti e secondi

period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();

4

Controlla l'esempio qui http://www.roseindia.net/java/beginners/DateDifferent.shtml Questo esempio ti dà la differenza in giorni, ore, minuti, secondi e milioni di secondi :).

import java.util.Calendar;
import java.util.Date;

public class DateDifferent {
    public static void main(String[] args) {
        Date date1 = new Date(2009, 01, 10);
        Date date2 = new Date(2009, 07, 01);
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar2.setTime(date2);
        long milliseconds1 = calendar1.getTimeInMillis();
        long milliseconds2 = calendar2.getTimeInMillis();
        long diff = milliseconds2 - milliseconds1;
        long diffSeconds = diff / 1000;
        long diffMinutes = diff / (60 * 1000);
        long diffHours = diff / (60 * 60 * 1000);
        long diffDays = diff / (24 * 60 * 60 * 1000);
        System.out.println("\nThe Date Different Example");
        System.out.println("Time in milliseconds: " + diff + " milliseconds.");
        System.out.println("Time in seconds: " + diffSeconds + " seconds.");
        System.out.println("Time in minutes: " + diffMinutes + " minutes.");
        System.out.println("Time in hours: " + diffHours + " hours.");
        System.out.println("Time in days: " + diffDays + " days.");
    }
}

3
-1 Questo è sbagliato a meno che le istanze Date non siano state derivate dalle ore UTC. Vedi la risposta di Jon Skeet.
sleske,

4

Utilizzare il fuso orario GMT per ottenere un'istanza del Calendario, impostare l'ora utilizzando il metodo set della classe Calendar. Il fuso orario GMT ha 0 offset (non molto importante) e il flag dell'ora legale impostato su false.

    final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 9);
    cal.set(Calendar.DAY_OF_MONTH, 29);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date startDate = cal.getTime();

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 12);
    cal.set(Calendar.DAY_OF_MONTH, 21);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date endDate = cal.getTime();

    System.out.println((endDate.getTime() - startDate.getTime()) % (1000l * 60l * 60l * 24l));

Non dimenticare di azzerare la parte in millisecondi, altrimenti è una buona risposta nel contesto di vecchie classi java.util.Dateecc. L'uso dell'hacking per impostare il fuso orario su GMT rende il codice insensibile agli effetti dell'ora legale.
Meno Hochschild,

4

Il seguente codice può darti l'output desiderato:

String startDate = "Jan 01 2015";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
LocalDate date = LocalDate.parse(startDate, formatter);

String currentDate = "Feb 11 2015";
LocalDate date1 = LocalDate.parse(currentDate, formatter);

System.out.println(date1.toEpochDay() - date.toEpochDay());

3
Puoi spiegare esattamente cosa fa il tuo codice? La domanda sembra porre un delta temporale e, a prima vista, il tuo codice sembrerebbe restituire un delta del giorno?
GHC,

4
public static String getDifferenceBtwTime(Date dateTime) {

    long timeDifferenceMilliseconds = new Date().getTime() - dateTime.getTime();
    long diffSeconds = timeDifferenceMilliseconds / 1000;
    long diffMinutes = timeDifferenceMilliseconds / (60 * 1000);
    long diffHours = timeDifferenceMilliseconds / (60 * 60 * 1000);
    long diffDays = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24);
    long diffWeeks = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 7);
    long diffMonths = (long) (timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 30.41666666));
    long diffYears = (long)(timeDifferenceMilliseconds / (1000 * 60 * 60 * 24 * 365));

    if (diffSeconds < 1) {
        return "one sec ago";
    } else if (diffMinutes < 1) {
        return diffSeconds + " seconds ago";
    } else if (diffHours < 1) {
        return diffMinutes + " minutes ago";
    } else if (diffDays < 1) {
        return diffHours + " hours ago";
    } else if (diffWeeks < 1) {
        return diffDays + " days ago";
    } else if (diffMonths < 1) {
        return diffWeeks + " weeks ago";
    } else if (diffYears < 12) {
        return diffMonths + " months ago";
    } else {
        return diffYears + " years ago";
    }
}   

3
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;

5
-1 Questo è sbagliato a meno che le istanze Date non siano state derivate dalle ore UTC. Vedi la risposta di Jon Skeet.
sleske,

5
@Sleske non hai ragione. Ha già perso le informazioni sul fuso orario usandoDate , quindi questo confronto è il migliore che si può ottenere date le circostanze.
Bozho,

1
OK, suppongo che abbiamo entrambi ragione. È vero che dipende da dove proviene l'istanza Date. Tuttavia, è un errore così comune che dovrebbe essere menzionato.
sleske,

Quando utilizzo la tua soluzione, viene visualizzato il messaggio: Digita mismatch: impossibile convertire da long a int. Penso che dovresti anche aggiungere il casting o mi sto perdendo qualcosa?
Ad Infinitum,

3

La cosa migliore da fare è

(Date1-Date2)/86 400 000 

Quel numero è il numero di millisecondi in un giorno.

Una data-altra data ti dà la differenza in millisecondi.

Raccogli la risposta in doppio variabile.


Si perché no? Non capisco il punto della domanda in qualche modo: OP ha una differenza in ms ... e ci sono un certo numero di ms in un giorno (OK con alcune regolazioni astronomiche una volta su una luna blu, ma OP non dire che deve essere preciso quanto gli astronomi ne hanno bisogno ...)
Mike Rodent,

3

Ecco una soluzione Java 7 corretta in O (1) senza dipendenze.

public static int countDaysBetween(Date date1, Date date2) {

    Calendar c1 = removeTime(from(date1));
    Calendar c2 = removeTime(from(date2));

    if (c1.get(YEAR) == c2.get(YEAR)) {

        return Math.abs(c1.get(DAY_OF_YEAR) - c2.get(DAY_OF_YEAR)) + 1;
    }
    // ensure c1 <= c2
    if (c1.get(YEAR) > c2.get(YEAR)) {
        Calendar c = c1;
        c1 = c2;
        c2 = c;
    }
    int y1 = c1.get(YEAR);
    int y2 = c2.get(YEAR);
    int d1 = c1.get(DAY_OF_YEAR);
    int d2 = c2.get(DAY_OF_YEAR);

    return d2 + ((y2 - y1) * 365) - d1 + countLeapYearsBetween(y1, y2) + 1;
}

private static int countLeapYearsBetween(int y1, int y2) {

    if (y1 < 1 || y2 < 1) {
        throw new IllegalArgumentException("Year must be > 0.");
    }
    // ensure y1 <= y2
    if (y1 > y2) {
        int i = y1;
        y1 = y2;
        y2 = i;
    }

    int diff = 0;

    int firstDivisibleBy4 = y1;
    if (firstDivisibleBy4 % 4 != 0) {
        firstDivisibleBy4 += 4 - (y1 % 4);
    }
    diff = y2 - firstDivisibleBy4 - 1;
    int divisibleBy4 = diff < 0 ? 0 : diff / 4 + 1;

    int firstDivisibleBy100 = y1;
    if (firstDivisibleBy100 % 100 != 0) {
        firstDivisibleBy100 += 100 - (firstDivisibleBy100 % 100);
    }
    diff = y2 - firstDivisibleBy100 - 1;
    int divisibleBy100 = diff < 0 ? 0 : diff / 100 + 1;

    int firstDivisibleBy400 = y1;
    if (firstDivisibleBy400 % 400 != 0) {
        firstDivisibleBy400 += 400 - (y1 % 400);
    }
    diff = y2 - firstDivisibleBy400 - 1;
    int divisibleBy400 = diff < 0 ? 0 : diff / 400 + 1;

    return divisibleBy4 - divisibleBy100 + divisibleBy400;
}


public static Calendar from(Date date) {

    Calendar c = Calendar.getInstance();
    c.setTime(date);

    return c;
}


public static Calendar removeTime(Calendar c) {

    c.set(HOUR_OF_DAY, 0);
    c.set(MINUTE, 0);
    c.set(SECOND, 0);
    c.set(MILLISECOND, 0);

    return c;
}

2

Questo è probabilmente il modo più semplice per farlo - forse è perché sto codificando in Java (con le sue librerie di data e ora sicuramente ingombranti) per un po 'di tempo, ma quel codice mi sembra "semplice e carino"!

Sei soddisfatto del risultato restituito in millisecondi o fa parte della tua domanda che preferiresti che fosse restituito in un formato alternativo?


2

Non utilizzando l'API standard, no. Puoi farlo da solo facendo qualcosa del genere:

class Duration {
    private final TimeUnit unit;
    private final long length;
    // ...
}

Oppure puoi usare Joda :

DateTime a = ..., b = ...;
Duration d = new Duration(a, b);

2

Solo per rispondere alla domanda iniziale:

Inserisci il codice seguente in una funzione come Long getAge () {}

Date dahora = new Date();
long MillisToYearsByDiv = 1000l *60l * 60l * 24l * 365l;
long javaOffsetInMillis = 1990l * MillisToYearsByDiv;
long realNowInMillis = dahora.getTime() + javaOffsetInMillis;
long realBirthDayInMillis = this.getFechaNac().getTime() + javaOffsetInMillis;
long ageInMillis = realNowInMillis - realBirthDayInMillis;

return ageInMillis / MillisToYearsByDiv;

Il più importante qui è lavorare con numeri lunghi durante la moltiplicazione e la divisione. E, naturalmente, l'offset che Java applica nel suo calcolo delle Date.

:)


2

Poiché la domanda è taggata con Scala,

import scala.concurrent.duration._
val diff = (System.currentTimeMillis() - oldDate.getTime).milliseconds
val diffSeconds = diff.toSeconds
val diffMinutes = diff.toMinutes
val diffHours = diff.toHours
val diffDays = diff.toDays

2

Dopo aver cercato tutte le altre risposte, per mantenere il tipo di data Java 7 ma essere più precisi / standard con l'approccio diff Java 8,

public static long daysBetweenDates(Date d1, Date d2) {
    Instant instant1 = d1.toInstant();
    Instant instant2 = d2.toInstant();
    long diff = ChronoUnit.DAYS.between(instant1, instant2);
    return diff;
}

1

prova questo:

int epoch = (int) (new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse("01/01/1970  00:00:00").getTime() / 1000);

puoi modificare la stringa nel parametro parse () metodi.

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.