Différence en jours entre deux dates en Java?

Je dois trouver le nombre de jours entre deux dates : l’une provient d’un rapport et l’autre est la date actuelle. Mon extrait:

int age=calculateDifference(agingDate, today); 

Ici calculateDifference est une méthode privée, agingDate et today sont des objects Date , juste pour votre clarification. J’ai suivi deux articles d’un forum Java, Thread 1 / Thread 2 .

Cela fonctionne très bien dans un programme autonome bien que lorsque j’inclus ceci dans ma logique pour lire le rapport, j’obtiens une différence de valeurs inhabituelle.

Pourquoi ça se passe et comment puis-je le réparer?

MODIFIER :

Je reçois un plus grand nombre de jours par rapport au nombre réel de jours.

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

Remarque :

Malheureusement, aucune des réponses ne m’a aidé à résoudre le problème. J’ai accompli ce problème avec l’aide de la bibliothèque Joda-time .

Je vous suggère d’utiliser l’excellente bibliothèque Joda Time au lieu des java.util.Date et amis défectueux. Vous pourriez simplement écrire

 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 

Il se peut que je sois trop en retard pour rejoindre le jeu mais que diable hein? 🙂

Pensez-vous que c’est un problème de threading? Comment utilisez-vous le résultat de cette méthode par exemple? OU

Pouvons-nous changer votre code pour faire quelque chose d’aussi simple que:

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

Le diff / (24 * etc) ne prend pas en compte le Fuseau horaire, donc si votre fuseau horaire par défaut a un DST, il peut désactiver le calcul.

Ce lien a une belle petite implémentation.

Voici la source du lien ci-dessus en cas de panne du lien:

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

et

 /** 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

Dans Java 8 et versions ultérieures, utilisez le framework java.time ( Tutorial ).

Duration

La classe Duration représente une durée en nombre de secondes plus une fraction de seconde. Il peut compter des jours, des heures, des minutes et des secondes.

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

ChronoUnit

Si tout ce dont vous avez besoin est le nombre de jours, vous pouvez également utiliser la énumération ChronoUnit . Notez que les méthodes de calcul renvoient un long plutôt que l’ int .

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

Cela dépend de ce que vous définissez comme étant la différence. Pour comparer deux dates à minuit, vous pouvez faire.

 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(Ssortingng startDate, Ssortingng 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(Ssortingng[] 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; } } 

Solution utilisant la différence entre les millisecondes et l’arrondi correct pour les dates de l’heure d’été:

 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 } 

Une note: bien sûr, les dates doivent être dans un fuseau horaire.

Le code important:

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

Si vous ne voulez pas de ronds, vous pouvez utiliser les dates UTC,

Illustration du problème: (Mon code calcule le delta en semaines, mais le même problème s’applique au delta en jours)

Voici une implémentation très raisonnable:

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

Mais ce test échouera:

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

La raison est:

Lun. Mars 09 00:00:00 HAE 2009 = 1,236,571,200,000
Lun 23 février 00:00:00 EST 2009 = 1,235,365,200,000
MillisPerWeek = 604 800 000
Ainsi,
(Mar09 – Feb23) / MillisPerWeek =
1 206 000 000/604 800 000 = 1 994 …

mais quiconque regarde un calendrier conviendra que la réponse est 2.

J’utilise cette fonction:

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

ma fonction:

 import java.util.Date; public long DATEDIFF(Ssortingng date1, Ssortingng 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; } 

Regardez les méthodes getFragmentInDays dans cette classe Apache commons-lang DateUtils .

Sur la base de la réponse de @ Mad_Troll, j’ai développé cette méthode.

J’ai exécuté environ 30 scénarios de test, c’est la seule méthode qui gère correctement les fragments de sous-journée.

Exemple: Si vous passez maintenant & maintenant + 1 milliseconde, c’est toujours le même jour. Faire 1-1-13 23:59:59.098 à 1-1-13 23:59:59.099 renvoie 0 jour, correctement; toutes les autres méthodes affichées ici ne le feront pas correctement.

À noter qu’il ne se soucie pas de la manière dont vous les mettez, si votre date de fin est antérieure à votre date de début, il comptera à rebours.

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

Vous pouvez supprimer les annotations @NotNull , celles-ci sont utilisées par Intellij pour parsingr le code à la volée

Vous dites que “fonctionne bien dans un programme autonome”, mais que vous obtenez “des valeurs de différence inhabituelles” lorsque vous “incluez cela dans ma logique pour lire le rapport”. Cela suggère que votre rapport contient des valeurs pour lesquelles il ne fonctionne pas correctement et que votre programme autonome ne contient pas ces valeurs. Au lieu d’un programme autonome, je suggère un cas de test. Ecrivez un scénario de test comme vous le feriez avec un programme autonome, en sous-classant la classe TestCase de JUnit. Maintenant, vous pouvez exécuter un exemple très spécifique, en sachant à quelle valeur vous vous attendez (et ne le donnez pas aujourd’hui pour la valeur du test, car aujourd’hui change avec le temps). Si vous insérez les valeurs que vous avez utilisées dans le programme autonome, vos tests seront probablement réussis. C’est bien, vous voulez que ces cas continuent à fonctionner. Maintenant, ajoutez une valeur à votre rapport, celle qui ne fonctionne pas correctement. Votre nouveau test échouera probablement. Déterminez pourquoi il échoue, corrigez-le et passez au vert (tous les tests réussissent). Exécutez votre rapport. Voir ce qui est encore cassé; écrire un test faites le passer. Très bientôt, votre rapport fonctionnera.

Cent lignes de code pour cette fonction de base ???

Juste une méthode simple:

 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 réponse de Vitalii Fedorenko est correcte, décrivant comment effectuer ce calcul de manière moderne avec les classes java.time ( Duration et ChronoUnit ) intégrées à Java 8 et ChronoUnit ultérieures (et scopes sur Java 6 et 7 et sur Android ).

Days

Si vous utilisez régulièrement un certain nombre de jours dans votre code, vous pouvez remplacer de simples entiers par l’utilisation d’une classe. La classe Days peut être trouvée dans le projet ThreeTen-Extra , une extension de java.time et la preuve de possibles ajouts futurs à java.time. La classe Days fournit un moyen sûr de représenter un nombre de jours dans votre application. La classe comprend des constantes pratiques pour ZERO et ONE .

Étant donné les anciens objects java.util.Date obsolètes dans la Question, convertissez-les d’ java.time.Instant objects java.time.Instant modernes. Les anciennes classes date-heure ont des méthodes nouvellement ajoutées pour faciliter la conversion en java.time, par exemple java.util.Date::toInstant .

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

Transmettez les deux objects Instant à la méthode d’usine pour org.threeten.extra.Days .

Dans l’implémentation actuelle (2016-06), il s’agit d’un wrapper appelant java.time.temporal.ChronoUnit.DAYS.between , lisez la doc de la classe ChronoUnit pour plus de détails. Pour être clair: tous les DAYS majuscule sont dans l’énumération ChronoUnit tandis que les Days d’initialisation sont une classe de ThreeTen-Extra.

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

Vous pouvez transmettre ces objects Days autour de votre propre code. Vous pouvez sérialiser en une chaîne au format standard ISO 8601 en appelant toSsortingng . Ce format de PnD utilise un P pour marquer le début et D signifie «jours», avec un nombre de jours intermédiaires. Les classes java.time et ThreeTen-Extra utilisent par défaut ces formats standard lors de la génération et de l’parsing de chaînes représentant des valeurs date-heure.

 Ssortingng output = days.toSsortingng(); 

P3D

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

Ce code calcule les jours entre deux chaînes de date:

  static final long MILLI_SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24; static final Ssortingng DATE_FORMAT = "dd-MM-yyyy"; public long daysBetween(Ssortingng fromDateStr, Ssortingng 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; } 

Si vous recherchez une solution qui renvoie le nombre ou les jours appropriés, par exemple entre 11/30/2014 23:59 et 12/01/2014 00:01 voici la solution utilisant Joda Time.

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

Cette implémentation renverra 1 comme différence en jours. La plupart des solutions affichées ici calculent la différence en millisecondes entre deux dates. Cela signifie que 0 sera renvoyé car il y a seulement 2 minutes de différence entre ces deux dates.

J’ai déjà écrit à ce sujet. Ceci est un repost de Calcul de la différence entre deux instances de date 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)); } 

Vous devez utiliser la bibliothèque Joda Time car Java Util Date renvoie parfois des valeurs incorrectes.

Joda vs Java Date d’utilisation

Par exemple des jours entre hier (jj-mm-aaaa, 12-07-2016) et le premier jour de l’année 1957 (jj-mm-aaaa, 01-01-1957):

 public class Main { public static void main(Ssortingng[] 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); } 

Je vous conseille donc d’utiliser la bibliothèque Joda Time.

Je l’ai fait de cette façon. c’est 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;