Differenza tra giorni tra due date in Java?

Devo trovare il numero di giorni tra due date : una proviene da un rapporto e una è la data corrente. Il mio frammento:

int age=calculateDifference(agingDate, today); 

Qui calculateDifference è un metodo privato, agingDate e today sono oggetti Date , solo per i tuoi chiarimenti. Ho seguito due articoli da un forum Java, Thread 1 / Thread 2 .

Funziona bene in un programma standalone anche se quando includo questo nella mia logica per leggere dal rapporto ottengo un’insolita differenza di valori.

Perché sta accadendo e come posso risolverlo?

MODIFICARE :

Sto ottenendo un numero maggiore di giorni rispetto alla quantità effettiva di giorni.

 public static int calculateDifference(Date a, Date b) { int tempDifference = 0; int difference = 0; Calendar earlier = Calendar.getInstance(); Calendar later = Calendar.getInstance(); if (a.compareTo(b) < 0) { earlier.setTime(a); later.setTime(b); } else { earlier.setTime(b); later.setTime(a); } while (earlier.get(Calendar.YEAR) != later.get(Calendar.YEAR)) { tempDifference = 365 * (later.get(Calendar.YEAR) - earlier.get(Calendar.YEAR)); difference += tempDifference; earlier.add(Calendar.DAY_OF_YEAR, tempDifference); } if (earlier.get(Calendar.DAY_OF_YEAR) != later.get(Calendar.DAY_OF_YEAR)) { tempDifference = later.get(Calendar.DAY_OF_YEAR) - earlier.get(Calendar.DAY_OF_YEAR); difference += tempDifference; earlier.add(Calendar.DAY_OF_YEAR, tempDifference); } return difference; } 

Nota :

Sfortunatamente, nessuna delle risposte mi ha aiutato a risolvere il problema. Ho raggiunto questo problema con l’aiuto della libreria Joda-time .

Ti suggerirei di utilizzare l’eccellente libreria di Joda Time al posto del java.util.Date e degli amici difettosi. Potresti semplicemente scrivere

 import java.util.Date; import org.joda.time.DateTime; import org.joda.time.Days; Date past = new Date(110, 5, 20); // June 20th, 2010 Date today = new Date(110, 6, 24); // July 24th int days = Days.daysBetween(new DateTime(past), new DateTime(today)).getDays(); // => 34 

Potrei essere in ritardo per partecipare al gioco ma che diamine huh? 🙂

Pensi che questo sia un problema di threading? Come stai usando l’output di questo metodo, ad esempio? O

Possiamo cambiare il tuo codice per fare qualcosa di semplice come:

 Calendar calendar1 = Calendar.getInstance(); Calendar calendar2 = Calendar.getInstance(); calendar1.set(); calendar2.set(); 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."); } 

Il diff / (24 * ecc.) Non tiene conto del fuso orario, quindi se il fuso orario predefinito ha un fuso orario, può eliminare il calcolo.

Questo link ha una bella piccola implementazione.

Ecco la fonte del link sopra nel caso in cui il link si interrompa:

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

e

 /** Using Calendar - THE CORRECT (& Faster) WAY**/ public static long daysBetween(final Calendar startDate, final Calendar endDate) { //assert: startDate must be before endDate int MILLIS_IN_DAY = 1000 * 60 * 60 * 24; long endInstant = endDate.getTimeInMillis(); int presumedDays = (int) ((endInstant - startDate.getTimeInMillis()) / MILLIS_IN_DAY); Calendar cursor = (Calendar) startDate.clone(); cursor.add(Calendar.DAY_OF_YEAR, presumedDays); long instant = cursor.getTimeInMillis(); if (instant == endInstant) return presumedDays; final int step = instant < endInstant ? 1 : -1; do { cursor.add(Calendar.DAY_OF_MONTH, step); presumedDays += step; } while (cursor.getTimeInMillis() != endInstant); return presumedDays; } 

java.time

In Java 8 e versioni successive, utilizzare il framework java.time ( Tutorial ).

Duration

La class Duration rappresenta un intervallo di tempo in un numero di secondi più un secondo frazionario. Può contare giorni, ore, minuti e secondi.

 ZonedDateTime now = ZonedDateTime.now(); ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10); Duration duration = Duration.between(oldDate, now); System.out.println(duration.toDays()); 

ChronoUnit

Se tutto ciò di cui hai bisogno è il numero di giorni, in alternativa puoi usare l’ ChronoUnit . Si noti che i metodi di calcolo restituiscono una long piuttosto che una int .

 long days = ChronoUnit.DAYS.between( then, now ); 

Dipende da ciò che definisci come differenza. Puoi confrontare due date a mezzanotte.

 long day1 = ...; // in milliseconds. long day2 = ...; // in milliseconds. long days = (day2 - day1) / 86400000; 
 import java.util.Calendar; import java.util.Date; public class Main { public static long calculateDays(String startDate, String endDate) { Date sDate = new Date(startDate); Date eDate = new Date(endDate); Calendar cal3 = Calendar.getInstance(); cal3.setTime(sDate); Calendar cal4 = Calendar.getInstance(); cal4.setTime(eDate); return daysBetween(cal3, cal4); } public static void main(String[] args) { System.out.println(calculateDays("2012/03/31", "2012/06/17")); } /** 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; } } 

Soluzione che utilizza la differenza tra il tempo in millisecondi, con arrotondamento corretto per le date dell’ora legale:

 public static long daysDiff(Date from, Date to) { return daysDiff(from.getTime(), to.getTime()); } public static long daysDiff(long from, long to) { return Math.round( (to - from) / 86400000D ); // 1000 * 60 * 60 * 24 } 

Una nota: certo, le date devono essere in un certo fuso orario.

Il codice importante:

 Math.round( (to - from) / 86400000D ) 

Se non vuoi round, puoi usare le date UTC,

Illustrazione del problema: (Il mio codice calcola il delta in settimane, ma lo stesso problema si applica con delta in giorni)

Ecco una implementazione dall’aspetto molto ragionevole:

 public static final long MILLIS_PER_WEEK = 7L * 24L * 60L * 60L * 1000L; static public int getDeltaInWeeks(Date latterDate, Date earlierDate) { long deltaInMillis = latterDate.getTime() - earlierDate.getTime(); int deltaInWeeks = (int)(deltaInMillis / MILLIS_PER_WEEK); return deltaInWeeks; } 

Ma questo test fallirà:

 public void testGetDeltaInWeeks() { delta = AggregatedData.getDeltaInWeeks(dateMar09, dateFeb23); assertEquals("weeks between Feb23 and Mar09", 2, delta); } 

Il motivo è:

Lun mar 09 00:00:00 EDT 2009 = 1.236.571.200.000
Lun 23 feb 00:00:00 EST 2009 = 1.235.365.200.000
MillisPerWeek = 604,800,000
Così,
(Mar09 – Feb23) / MillisPerWeek =
1.206.000.000 / 604.800.000 = 1.994 …

ma chiunque guardi un calendario concorderebbe che la risposta è 2.

Io uso questa funzione:

 DATEDIFF("31/01/2016", "01/03/2016") // me return 30 days 

la mia funzione:

 import java.util.Date; public long DATEDIFF(String date1, String date2) { long MILLISECS_PER_DAY = 24 * 60 * 60 * 1000; long days = 0l; SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); // "dd/MM/yyyy HH:mm:ss"); Date dateIni = null; Date dateFin = null; try { dateIni = (Date) format.parse(date1); dateFin = (Date) format.parse(date2); days = (dateFin.getTime() - dateIni.getTime())/MILLISECS_PER_DAY; } catch (Exception e) { e.printStackTrace(); } return days; } 

Guarda i metodi getFragmentInDays in questa class di apache commons-lang DateUtils .

Sulla base della risposta di @ Mad_Troll, ho sviluppato questo metodo.

Ho eseguito circa 30 casi di test contro di esso, è l’unico metodo che gestisce correttamente i frammenti del giorno secondario.

Esempio: se passi ora e ora + 1 millisecondo è ancora lo stesso giorno. Da 1-1-13 23:59:59.098 a 1-1-13 23:59:59.099 restituisce 0 giorni, correttamente; tutti gli altri metodi pubblicati qui non lo faranno correttamente.

Vale la pena notare che non importa in che modo li metti in, Se la tua data di fine è precedente alla tua data di inizio, verrà conteggiata all’indietro.

 /** * This is not quick but if only doing a few days backwards/forwards then it is very accurate. * * @param startDate from * @param endDate to * @return day count between the two dates, this can be negative if startDate is after endDate */ public static long daysBetween(@NotNull final Calendar startDate, @NotNull final Calendar endDate) { //Forwards or backwards? final boolean forward = startDate.before(endDate); // Which direction are we going final int multiplier = forward ? 1 : -1; // The date we are going to move. final Calendar date = (Calendar) startDate.clone(); // Result long daysBetween = 0; // Start at millis (then bump up until we go back a day) int fieldAccuracy = 4; int field; int dayBefore, dayAfter; while (forward && date.before(endDate) || !forward && endDate.before(date)) { // We start moving slowly if no change then we decrease accuracy. switch (fieldAccuracy) { case 4: field = Calendar.MILLISECOND; break; case 3: field = Calendar.SECOND; break; case 2: field = Calendar.MINUTE; break; case 1: field = Calendar.HOUR_OF_DAY; break; default: case 0: field = Calendar.DAY_OF_MONTH; break; } // Get the day before we move the time, Change, then get the day after. dayBefore = date.get(Calendar.DAY_OF_MONTH); date.add(field, multiplier); dayAfter = date.get(Calendar.DAY_OF_MONTH); // This shifts lining up the dates, one field at a time. if (dayBefore == dayAfter && date.get(field) == endDate.get(field)) fieldAccuracy--; // If day has changed after moving at any accuracy level we bump the day counter. if (dayBefore != dayAfter) { daysBetween += multiplier; } } return daysBetween; } 

È ansible rimuovere le annotazioni @NotNull , utilizzate da Intellij per eseguire al volo l’analisi del codice

Dici che “funziona bene in un programma standalone”, ma che ottieni “valori di differenza insoliti” quando “includi questo nella mia logica per leggere dal rapporto”. Ciò suggerisce che il tuo report ha alcuni valori per i quali non funziona correttamente e il tuo programma standalone non ha quei valori. Invece di un programma standalone, suggerisco un caso di test. Scrivi un test case come faresti con un programma standalone, sottoclassi dalla class TestCase di JUnit. Ora puoi eseguire un esempio molto specifico, sapendo quale valore ti aspetti (e non darlo oggi per il valore del test, perché oggi cambia nel tempo). Se inserisci i valori che hai usato nel programma standalone, probabilmente i tuoi test passeranno. È grandioso – vuoi che quei casi continuino a funzionare. Ora aggiungi un valore dal tuo rapporto, uno che non funziona correttamente. Probabilmente il tuo nuovo test fallirà. Scopri perché non funziona, risolvilo e diventa verde (tutti i test che passano). Esegui il tuo rapporto. Guarda cosa è ancora rotto; scrivere un test; fallo passare. Molto presto scoprirai che il tuo rapporto funziona.

Cento linee di codice per questa funzione di base ???

Solo un metodo semplice:

 protected static int calculateDayDifference(Date dateAfter, Date dateBefore){ return (int)(dateAfter.getTime()-dateBefore.getTime())/(1000 * 60 * 60 * 24); // MILLIS_IN_DAY = 1000 * 60 * 60 * 24; } 
 public static int getDifferenceIndays(long timestamp1, long timestamp2) { final int SECONDS = 60; final int MINUTES = 60; final int HOURS = 24; final int MILLIES = 1000; long temp; if (timestamp1 < timestamp2) { temp = timestamp1; timestamp1 = timestamp2; timestamp2 = temp; } Calendar startDate = Calendar.getInstance(TimeZone.getDefault()); Calendar endDate = Calendar.getInstance(TimeZone.getDefault()); endDate.setTimeInMillis(timestamp1); startDate.setTimeInMillis(timestamp2); if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) { int day1 = endDate.get(Calendar.DAY_OF_MONTH); int day2 = startDate.get(Calendar.DAY_OF_MONTH); if (day1 == day2) { return 0; } else { return 1; } } int diffDays = 0; startDate.add(Calendar.DAY_OF_MONTH, diffDays); while (startDate.before(endDate)) { startDate.add(Calendar.DAY_OF_MONTH, 1); diffDays++; } return diffDays; } 

ThreeTen-Extra

La risposta di Vitalii Fedorenko è corretta, descrivendo come eseguire questo calcolo in modo moderno con le classi java.time ( Duration e ChronoUnit ) integrate in Java 8 e ChronoUnit successive (e back-porting su Java 6 e 7 e su Android ).

Days

Se si utilizza regolarmente un numero di giorni nel codice, è ansible sostituire i semplici numeri interi con l’uso di una class. La class Days può essere trovata nel progetto ThreeTen-Extra , un’estensione di java.time e terreno di prova per eventuali aggiunte future a java.time. La class Days fornisce un modo sicuro per il tipo di rappresentare un numero di giorni nella tua applicazione. La class include costanti convenienti per ZERO e ONE .

Dati i vecchi oggetti java.util.Date obsoleti nella domanda, convertili prima in oggetti java.time.Instant moderni. Le vecchie classi data-ora hanno nuovi metodi aggiunti per facilitare la conversione in java.time, ad esempio java.util.Date::toInstant .

 Instant start = utilDateStart.toInstant(); // Inclusive. Instant stop = utilDateStop.toInstant(); // Exclusive. 

Passa entrambi gli oggetti Instant al metodo factory per org.threeten.extra.Days .

Nell’attuale implementazione (2016-06) questo è un wrapper che chiama java.time.temporal.ChronoUnit.DAYS.between , leggi il ChronoUnit class ChronoUnit per i dettagli. Per essere chiari: tutti i DAYS maiuscoli si trovano ChronoUnit mentre i cap initial Days sono una class di ThreeTen-Extra.

 Days days = Days.between( start , stop ); 

Puoi passare questi oggetti Days attorno al tuo codice. È ansible serializzare su una stringa nel formato ISO 8601 standard chiamando toString . Questo formato di PnD usa una P per segnare l’inizio e D significa “giorni”, con un numero di giorni nel mezzo. Sia le classi java.time che ThreeTen-Extra utilizzano questi formati standard per impostazione predefinita durante la generazione e l’analisi di stringhe che rappresentano valori di data e ora.

 String output = days.toString(); 

P3D

 Days days = Days.parse( "P3D" ); 

Questo codice calcola i giorni tra 2 stringhe di data:

  static final long MILLI_SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24; static final String DATE_FORMAT = "dd-MM-yyyy"; public long daysBetween(String fromDateStr, String toDateStr) throws ParseException { SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT); Date fromDate; Date toDate; fromDate = format.parse(fromDateStr); toDate = format.parse(toDateStr); return (toDate.getTime() - fromDate.getTime()) / MILLI_SECONDS_IN_A_DAY; } 

Se stai cercando una soluzione che restituisca il numero oi giorni corretti tra es. 11/30/2014 23:59 e 12/01/2014 00:01 ecco la soluzione utilizzando Joda Time.

 private int getDayDifference(long past, long current) { DateTime currentDate = new DateTime(current); DateTime pastDate = new DateTime(past); return currentDate.getDayOfYear() - pastDate.getDayOfYear(); } 

Questa implementazione restituirà 1 come differenza in giorni. La maggior parte delle soluzioni pubblicate qui calcola la differenza in millisecondi tra due date. Significa che 0 verrebbe restituito perché c’è solo una differenza di 2 minuti tra queste due date.

Ho già scritto a riguardo. Si tratta di un repost dal calcolo della differenza tra due istanze di data Java .

 public int getDiffernceInDays(long timeAfter, long timeBefore) { Calendar calendarAfter = Calendar.getInstance(); calendarAfter.setTime(new Date(timeAfter)); Calendar calendarNewAfter = Calendar.getInstance(); calendarNewAfter.set(calendarAfter.get(Calendar.YEAR), calendarAfter.get(Calendar.MONTH), calendarAfter.get(Calendar.DAY_OF_MONTH)); Calendar calendarBefore = Calendar.getInstance(); calendarBefore.setTime(new Date(timeBefore)); Calendar calendarNewBefore = Calendar.getInstance(); calendarNewBefore.set(calendarBefore.get(Calendar.YEAR), calendarBefore.get(Calendar.MONTH), calendarBefore.get(Calendar.DAY_OF_MONTH)); return (int) ((calendarNewAfter.getTime().getTime() - calendarNewBefore.getTime().getTime()) / (24 * 60 * 60 * 1000)); } 

È necessario utilizzare la libreria Joda Time poiché la data Util Java restituisce talvolta valori errati.

Joda vs Java Util Date

Per esempio giorni tra ieri (gg-mm-aaaa, 12-07-2016) e primo giorno dell’anno nel 1957 (gg-mm-aaaa, 01-01-1957):

 public class Main { public static void main(String[] args) { SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); Date date = null; try { date = format.parse("12-07-2016"); } catch (ParseException e) { e.printStackTrace(); } //Try with Joda - prints 21742 System.out.println("This is correct: " + getDaysBetweenDatesWithJodaFromYear1957(date)); //Try with Java util - prints 21741 System.out.println("This is not correct: " + getDaysBetweenDatesWithJavaUtilFromYear1957(date)); } private static int getDaysBetweenDatesWithJodaFromYear1957(Date date) { DateTime jodaDateTime = new DateTime(date); DateTimeFormatter formatter = DateTimeFormat.forPattern("dd-MM-yyyy"); DateTime y1957 = formatter.parseDateTime("01-01-1957"); return Days.daysBetween(y1957 , jodaDateTime).getDays(); } private static long getDaysBetweenDatesWithJavaUtilFromYear1957(Date date) { SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); Date y1957 = null; try { y1957 = format.parse("01-01-1957"); } catch (ParseException e) { e.printStackTrace(); } return TimeUnit.DAYS.convert(date.getTime() - y1957.getTime(), TimeUnit.MILLISECONDS); } 

Quindi ti consiglio davvero di usare la libreria di Joda Time.

L’ho fatto in questo modo. è facile 🙂

 Date d1 = jDateChooserFrom.getDate(); Date d2 = jDateChooserTo.getDate(); Calendar day1 = Calendar.getInstance(); day1.setTime(d1); Calendar day2 = Calendar.getInstance(); day2.setTime(d2); int from = day1.get(Calendar.DAY_OF_YEAR); int to = day2.get(Calendar.DAY_OF_YEAR); int difference = to-from;