Calcul de la différence entre deux instances de date Java

433

J'utilise la java.util.Dateclasse Java dans Scala et je veux comparer un Dateobjet et l'heure actuelle. Je sais que je peux calculer le delta en utilisant getTime ():

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

Cependant, cela me laisse juste un longreprésentant des millisecondes. Existe-t-il un moyen plus simple et plus agréable d'obtenir un delta temporel?

pr1001
la source
10
Pourquoi pas d'amour pour le temps Joda? C'est à peu près la meilleure option si vous allez traiter des dates en java.
Docteur Jones
7
Veuillez vérifier ma solution élégante à 2 doublures, sans utiliser Joda et donner le résultat dans n'importe quelle TimeUnit à stackoverflow.com/a/10650881/82609
Sebastien Lorber
2
Honte à tous ceux qui recommandent l'heure Joda, et ne recommandent pas une vraie réponse Java ...
Zizouz212
2
@ Zizouz212 En ce qui concerne la recommandation de Joda-Time, les anciennes classes de date-heure regroupées avec Java sont mauvaises, très mauvaises, mal conçues, déroutantes et gênantes. Tellement mauvais que Joda-Time est devenu un énorme succès en tant que leur remplaçant. Tellement mauvais que même Sun / Oracle les a abandonnés et a adopté le package java.time dans le cadre de Java 8 et versions ultérieures. Les classes java.time sont inspirées de Joda-Time. Joda-Time et java.time sont dirigés par le même homme, Stephen Colbourne . Je dirais, « Honte à toute personne recommandant l' utilisation de Date, Calendaret SimpleDateFormat».
Basil Bourque
2
Alors que Joda Time était probablement une bonne réponse lorsque la question a été posée, aujourd'hui, la meilleure réponse pour quiconque peut utiliser Java 8 est d'utiliser java.time.Periodet / ou Duration. Voir la réponse de Basil Bourque ci-dessous .
Ole VV

Réponses:

198

L' DateAPI JDK est malheureusement horriblement cassée. Je recommande d'utiliser la bibliothèque Joda Time .

Joda Time a un concept d' intervalle de temps :

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

EDIT: Soit dit en passant, Joda a deux concepts: Intervalpour représenter un intervalle de temps entre deux instants de temps (représentent le temps entre 8h et 10h), et un Durationqui représente une durée sans les limites de temps réelles (par exemple, représentent deux heures!)

Si vous ne vous souciez que des comparaisons de temps, la plupart des Dateimplémentations (y compris celle du JDK) implémentent une Comparableinterface qui vous permet d'utiliser leComparable.compareTo()

notnoop
la source
btw - tu veux dire Comparable.compareTo(), pas Comparable.compare().
Scott Morrison
Joda-Time a trois classes pour représenter un intervalle de temps de différentes manières: Intervalle, Durée et Période. Cette bonne réponse traite de ces deux premiers. Voir ma réponse pour plus d'informations sur la période.
Basil Bourque
Java 8 a une nouvelle API de date et d'heure comme joda.
tbodt du
11
Le nouveau java.timepackage de Java 8 est inspiré de Joda-Time mais n'est pas un remplacement direct. Chacun a ses avantages et ses inconvénients. Heureusement, vous n'avez pas à choisir entre eux. Utilisez chacun pour ses points forts tant que vous faites attention à vos importdéclarations. Voir cette autre réponse par exemple de java.time.
Basil Bourque
6
Pour info, le projet Joda-Time est désormais en mode maintenance , l'équipe conseillant la migration vers les classes java.time . Voir Tutoriel par Oracle .
Basil Bourque
550

Diff simple (sans 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);
}

Et puis pouvez-vous appeler:

getDateDiff(date1,date2,TimeUnit.MINUTES);

pour obtenir le diff des 2 dates en unité de minutes.

TimeUnitest java.util.concurrent.TimeUnit, une énumération Java standard allant des nanos aux jours.


Différence lisible par l'homme (sans 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

La sortie est quelque chose comme Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}, avec les unités commandées.

Il vous suffit de convertir cette carte en une chaîne conviviale.


Attention

Les extraits de code ci-dessus calculent une différence simple entre 2 instants. Cela peut provoquer des problèmes lors d'un changement d'heure d'été, comme expliqué dans cet article . Cela signifie que si vous calculez la différence entre les dates sans heure, il se peut qu'il manque un jour / une heure.

À mon avis, la date diff est un peu subjective, surtout les jours. Tu peux:

  • compter le nombre de temps écoulé 24h: jour + 1 - jour = 1 jour = 24h

  • compter le nombre de temps écoulé, en prenant soin de l'heure d'été: jour + 1 - jour = 1 = 24h (mais en utilisant l'heure de minuit et l'heure d'été, il pourrait être 0 jour et 23h)

  • compter le nombre de day switches, ce qui signifie jour + 1 13h - jour 11h = 1 jour, même si le temps écoulé n'est que de 2h (ou 1h s'il y a une heure d'été: p)

Ma réponse est valable si votre définition de date diff les jours correspond au 1er cas

Avec JodaTime

Si vous utilisez JodaTime, vous pouvez obtenir le diff pour 2 instants (millies soutenu ReadableInstant) dates avec:

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

Mais vous pouvez également obtenir le diff pour les dates / heures locales:

// 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()
Sébastien Lorber
la source
Wow, vous pouvez vraiment apprendre de nouveaux tours à un vieux chien! Jamais entendu parler de cela auparavant, très utile pour traduire les différences de date en chaînes significatives.
Jeremy Goodell
@SebastienLorber Existe-t-il un moyen dans TimeUnit de calculer la différence ainsi? "L'alarme est réglée pour 3 jours, 4 heures et 12 minutes".
likejudo
des trucs géniaux m'ont vraiment fait gagner beaucoup de temps. Apprécier ton aide.
Lyju I Edwinson
J'ai perdu 3 jours de ma vie à gérer les dates Java et j'en ai jeté beaucoup et remplacé par ça. Je vous remercie.
user1091524
C'est la meilleure réponse que j'ai vue depuis que je suis sur stackoverflow! : D: D: D
Froid
153
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

Notez que cela fonctionne avec les dates UTC, donc la différence peut être un jour de congé si vous regardez les dates locales. Et le faire fonctionner correctement avec les dates locales nécessite une approche complètement différente en raison de l'heure d'été.

Michael Borgwardt
la source
6
Cela ne fonctionne pas correctement sur Android. Des erreurs d'arrondi existent. L'exemple du 19 au 21 mai indique 1 jour car il lance 1,99 à 1. Utilisez round avant de lancer à int.
Pratik Mandrekar
4
C'est la meilleure et la plus simple réponse. Lors du calcul d'une différence entre deux dates, les fuseaux horaires locaux se soustraient ... de sorte que la bonne réponse (sous forme de double) est donnée simplement par ((double) (newer.getTime () - old.getTime ()) / (86400.0 * 1000.0); ... en double, vous avez également le jour fractionnaire qui peut facilement être converti en HH: MM: ss
scottb
8
@scottb: le problème avec les dates locales est que vous pouvez avoir l'heure d'été, ce qui signifie que certains jours ont 23 ou 25 heures, ce qui peut potentiellement gâcher le résultat.
Michael Borgwardt,
1
@Steve: c'est 28 pour moi quand on les définit comme cette nouvelle Date (115, 2, 26); (faites attention au doc ​​API pour les params). Est-il possible que vous les analysiez en utilisant le format de date américain et en mode indulgent, de sorte que le 26/03/2015 soit interprété comme le 3e jour du 26e mois de 2015?
Michael Borgwardt
1
@Steve: hm, je ne sais pas pourquoi j'ai obtenu un résultat différent auparavant, mais maintenant je peux reproduire votre erreur. Les accolades dans votre code sont différentes de celles de ma réponse, ce qui entraîne une conversion en (endDate.getTime() - startDate.getTime())au intlieu du résultat final, et vous obtenez un débordement d'entier.
Michael Borgwardt
54

Utilisation du framework java.time intégré à 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());

Production:

ISO-8601: PT24H10M

Procès-verbal: 1450

Pour plus d'informations, consultez le didacticiel Oracle et la norme ISO 8601 .

Vitalii Fedorenko
la source
5
Ceci, ou utilisez Periodau lieu de Durationpour les dates.
Aphex
53

Vous devez définir votre problème plus clairement. Vous pouvez simplement prendre le nombre de millisecondes entre les deux Dateobjets et diviser par le nombre de millisecondes en 24 heures, par exemple ... mais:

  • Cela ne prendra pas en compte les fuseaux horaires - Dateest toujours en UTC
  • Cela ne prendra pas en compte l'heure d'été (où il peut y avoir des jours qui ne durent que 23 heures, par exemple)
  • Même au sein de l'UTC, combien de jours y a-t-il du 16 août 23h au 18 août 2h? Ce n'est que 27 heures, alors ça veut dire un jour? Ou devrait-il être de trois jours car il couvre trois dates?
Jon Skeet
la source
1
J'ai pensé java.util. La date n'était qu'un minuscule wrapper autour d'une représentation en millisecondes, interprétée dans le fuseau horaire local (par défaut). L'impression d'une date me donne une représentation du fuseau horaire local. Suis-je confus ici?
Adriaan Koster
46

tl; dr

Convertissez vos obsolètes java.util.Dateobjets à leur remplacement, java.time.Instant. Ensuite, calculez le temps écoulé comme 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

Format ISO 8601: PnYnMnDTnHnMnS

La norme sensée ISO 8601 définit une représentation textuelle concise d'une période de temps en nombre d'années, mois, jours, heures, etc. La norme appelle une telle période une durée . Le format est l' PnYnMnDTnHnMnSendroit où le Pmoyen "Période", le Tsépare la partie date de la partie heure, et entre les deux sont des nombres suivis d'une lettre.

Exemples:

  • P3Y6M4DT12H30M5S
    trois ans, six mois, quatre jours, douze heures, trente minutes et cinq secondes
  • PT4H30M
    Quatre heures et demie

java.time

Le framework java.time intégré à Java 8 et versions ultérieures supplante les anciennes java.util.Date/ java.util.Calendarclasses gênantes . Les nouvelles classes sont inspirées par le framework Joda-Time très réussi , destiné à lui succéder, de concept similaire mais ré-architecturé. Défini par JSR 310 . Prolongé par le projet ThreeTen-Extra . Voir le tutoriel .

Moment

La Instantclasse représente un moment sur la chronologie en UTC avec une résolution de nanosecondes (jusqu'à neuf (9) chiffres d'une fraction décimale).

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

Mieux vaut éviter les anciennes classes telles que Date/ Calendar. Mais si vous devez interagir avec l'ancien code qui n'a pas encore été mis à jour vers java.time , convertissez-le d'avant en arrière. Appelez de nouvelles méthodes de conversion ajoutées aux anciennes classes. Pour passer d'un java.util.Dateà un Instant, appelez Date::toInstant.

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

Durée

Les classes java.time ont divisé cette idée de représenter une période de temps en nombre d'années, mois, jours, heures, minutes, secondes en deux moitiés:

  • Period pendant des années, des mois, des jours
  • Duration pour jours, heures, minutes, secondes

Voici un exemple.

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

Dump sur console.

Les deux Periodet Durationutiliser l' ISO 8601 standard pour générer une représentation chaîne de leur valeur.

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

maintenant: 2015-11-26T00: 46: 48.016-05: 00 [Amérique / Montréal] à l'avenir: 2015-11-26T00: 46: 48.016-05: 00 [Amérique / Montréal] = PT1H3M

Java 9 ajoute des méthodes pour Durationobtenir la partie jours, la partie heures, la partie minutes et la partie secondes.

Vous pouvez obtenir le nombre total de jours ou d'heures ou de minutes ou de secondes ou de millisecondes ou de nanosecondes sur toute la durée.

long totalHours = duration.toHours();

Dans Java 9, la Durationclasse obtient de nouvelles méthodes pour renvoyer les différentes parties de jours, heures, minutes, secondes, millisecondes / nanosecondes. Appelez les to…Partméthodes suivantes : toDaysPart(), toHoursPart()et ainsi de suite.

ChronoUnit

Si vous ne vous souciez que d'une granularité de temps plus simple et plus grande, comme le «nombre de jours écoulés», utilisez l' ChronoUniténumération.

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

Un autre exemple.

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

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

120


À propos de java.time

Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciens gênants hérités des classes date-heure tels que java.util.Date, Calendar, et SimpleDateFormat.

Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers java.time.

Pour en savoir plus, consultez le didacticiel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .

Où obtenir les classes java.time?

Le projet ThreeTen-Extra étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour de futurs ajouts possibles à java.time. Vous trouverez peut - être des classes utiles ici, comme Interval, YearWeek, YearQuarteret plus .


Joda-Time

MISE À JOUR: Le projet Joda-Time est maintenant en mode maintenance , l'équipe conseillant la migration vers les classes java.time . Je laisse cette section intacte pour l'histoire.

La bibliothèque Joda-Time utilise ISO 8601 pour ses valeurs par défaut. Sa Periodclasse analyse et génère ces chaînes 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 );

Rendu:

period: PT4H30M
Basil Bourque
la source
C'est drôle que vous ayez commencé un mur de texte sans rapport avec la question avec "tl; dr". La question n'est pas de savoir comment obtenir l'horodatage d'il y a X ou en unités de temps X, mais comment obtenir le delta entre deux dates. C'est ça.
Buffalo
@Buffalo Je ne comprends pas votre commentaire. Ma réponse implique Period, Durationet ChronoUnit, trois classes dont le but est de déterminer le delta entre les points de temps. Veuillez indiquer quelles parties de mon «mur de texte» ne sont pas pertinentes. Et vous avez tort de dire que la Question demandait un «delta entre les dates»: La Question demandait un delta entre les Dateobjets, qui sont des moments date-heure, pas des «dates» malgré le nom malheureux de cette classe.
Basil Bourque
Il n'y a rien dans votre commentaire qui gère deux objets java.util.Date existants. J'ai essayé d'utiliser divers extraits de code dans mon code et je n'ai rien trouvé qui utilise un objet java.util.Date.
Buffalo
@Buffalo Assez juste, bonne critique. J'ai ajouté du code dans la section "tl; dr" convertissant de a java.util.Dateen an Instant(appelez simplement .toInstant). Et j'ai ajouté la Momentsection pour expliquer. Vous avez mentionné une paire d' Dateobjets, mais en fait, la question n'utilise qu'un seul Dateobjet existant et capture ensuite l'instant actuel, alors j'ai fait la même chose. Merci pour les commentaires! Astuce: renoncez à l'utilisation Date- Ces classes héritées sont vraiment un horrible gâchis.
Basil Bourque
23

Une alternative un peu plus simple:

System.currentTimeMillis() - oldDate.getTime()

Quant à "plus joli": eh bien, de quoi avez-vous besoin exactement? Le problème de la représentation des durées en nombre d'heures et de jours, etc., est que cela peut conduire à des inexactitudes et à des attentes erronées en raison de la complexité des dates (par exemple, les jours peuvent avoir 23 ou 25 heures en raison de l'heure d'été).

Michael Borgwardt
la source
22

L'utilisation d'une approche en millisecondes peut entraîner des problèmes dans certains paramètres régionaux.

Prenons, par exemple, la différence entre les deux dates 24/03/2007 et 25/03/2007 devrait être de 1 jour;

Cependant, en utilisant la route en millisecondes, vous obtiendrez 0 jours, si vous exécutez cela au Royaume-Uni!

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

La meilleure façon de l'implémenter est d'utiliser 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;  
}  
zasadnyy
la source
19
Pourriez-vous s'il vous plaît créditer l'auteur original de ce code et de la troisième phrase, dont l' entrée de blog date de 2007 ?
wchargin
N'est-ce pas un peu inefficace?
Gangnus
Cela ne fonctionne pas correctement. daysBetween (nouveau GregorianCalendar (2014,03,01), nouveau GregorianCalendar (2014,04,02))); renvoie 31, et il devrait renvoyer 32: timeanddate.com/date/…
marcolopes
5
@marcolopes - Vous vous trompez - car les mois civils sont basés sur zéro. Je suis sûr que vous voulez dire mars / avril, mais ce que vous testez est avril / juin qui est 31. Pour être sûr, écrivez-le comme -> nouveau GregorianCalendar (2014, Calendar.MARCH, 1) ....
Oncle Iroh
@UncleIroh, vous avez raison! J'ai raté ce fait important (les mois civils sont basés sur zéro). Je dois revoir cette question à nouveau.
marcolopes
22

Il existe de nombreuses façons de trouver la différence entre les dates et les heures. L'un des moyens les plus simples que je connaisse serait:

      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'instruction print n'est qu'un exemple - vous pouvez la formater comme vous le souhaitez.

JDGuide
la source
5
@ manoj kumar bardhan: bienvenue au débordement de pile: Comme vous le voyez, la question et les réponses ont des années. Votre réponse devrait ajouter plus à la question / réponse que celles existantes.
Jayan
3
Qu'en est-il des jours qui ont 23 ou 25 heures en raison d'une transition à l'heure d'été?
Joni
19

Étant donné que toutes les réponses ici sont correctes mais utilisent des bibliothèques java héritées ou tierces comme joda ou similaire, je vais simplement laisser tomber une autre façon en utilisant de nouvelles classes java.time dans Java 8 et versions ultérieures. Voir Oracle Tutorial .

Utiliser LocalDateet 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 );
ΦXocę 웃 Пepeúpa ツ
la source
9

La soustraction des dates en millisecondes fonctionne (comme décrit dans un autre article), mais vous devez utiliser HOUR_OF_DAY et non HOUR lors de l'effacement des parties temporelles de vos dates:

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
}
Malcolm Boekhoff
la source
1
C'est la meilleure méthode pour déterminer la différence entre deux dates de calendrier, sans sortir des bibliothèques standard. La plupart des autres réponses traitent une journée comme une période arbitraire de 24 heures. Si jamais des secondes intercalaires devaient être soustraites plutôt que ajoutées, le calcul final pourrait être décalé d'une unité en raison de la troncature, car la différence absolue pourrait être légèrement inférieure à un nombre entier de multiples de MSPERDAY.
JulianSymes
8

Si vous ne souhaitez pas utiliser JodaTime ou similaire, la meilleure solution est probablement la suivante:

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

Le nombre de ms par jour n'est pas toujours le même (en raison de l'heure d'été et des secondes intercalaires), mais il est très proche, et au moins les écarts dus à l'heure d'été s'annulent sur des périodes plus longues. Par conséquent, la division puis l'arrondi donneront un résultat correct (au moins tant que le calendrier local utilisé ne contient pas de sauts de temps étranges autres que l'heure d'été et les secondes intercalaires).

Notez que cela suppose toujours que date1et date2sont définis à la même heure de la journée. Pour différentes heures de la journée, vous devez d'abord définir ce que signifie «différence de date», comme l'a souligné Jon Skeet.

sleske
la source
La question est en date1.getTime()contre date2.getTime(). Ainsi, la différence entre le 2016-03-03 et le 2016-03-31 calculera 27 jours alors que vous en voudriez 28.
malat
@malat: Désolé, je ne peux pas suivre. Je viens de l'essayer - différent du 2016-03-03 au 2016-03-31 avec mon code calcule 28 jours. S'il calcule autre chose dans votre exemple, envisagez de le poser comme une question distincte.
sleske
Aussi, avez-vous lu ma mise en garde? "cela suppose toujours que date1 et date2 sont définies à la même heure". Avez-vous peut-être utilisé différentes heures de la journée dans votre test?
sleske
Ah oui! J'ai raté l'astuce avec Math.round(), qui semble sûre dans les calendriers du «monde réel». Désolé pour le bruit.
malat
8

Jetez un œil à Joda Time , qui est une API Date / Time améliorée pour Java et devrait fonctionner correctement avec Scala.

Rob H
la source
remplacé par java.time (JSR-310) dans Java 8
malat
5

Permettez-moi de montrer la différence entre Joda Interval et 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 
user674158
la source
5

Si vous avez besoin d'une chaîne de retour formatée comme "2 jours 03h 42m 07s", essayez ceci:

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;
}
Ingo
la source
2
Whoa, pourquoi lancer le vôtre quand Joda-Time fournit la classe Period déjà écrite et déboguée?
Basil Bourque
8
Pourquoi devrais-je télécharger une bibliothèque avec une taille de fichier compressée de 4,1 Mo et l'ajouter à mon projet, alors que je n'ai besoin que de 32 lignes de code ???
Ingo
1
Parce que Joda-Time est comme des croustilles: vous ne pouvez pas en manger une seule. Vous utiliserez Joda-Time partout. Et parce que Joda-Time est un code bien testé et bien porté. Et parce que Joda-Time analyse et génère des chaînes de durée ISO 8601 standard qui peuvent être utiles pour sérialiser ou signaler ces valeurs. Et parce que Joda-Time inclut des formateurs pour imprimer des représentations localisées de ces valeurs.
Basil Bourque
Tout votre code n'est pas testé. stdci-dessus n'est pas défini.
Basil Bourque
@Basil Bourque: Thx pour l'astuce. J'ai corrigé la source. Cette erreur provient de la traduction en anglais.
Ingo
5

Remarque: startDate et endDates sont -> 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();

et date de fin

Comme pour les jours, vous pouvez également obtenir des heures, des minutes et des secondes

period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();
Shravan Ramamurthy
la source
4

Consultez l'exemple ici http://www.roseindia.net/java/beginners/DateDifferent.shtml Cet exemple vous donne la différence en jours, heures, minutes, secondes et milli secondes :).

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.");
    }
}
YoK
la source
3
-1 C'est faux, sauf si les instances de Date sont dérivées des heures UTC. Voir la réponse de Jon Skeet.
sleske
4

Utilisez le fuseau horaire GMT pour obtenir une instance de Calendar, définissez l'heure à l'aide de la méthode set de la classe Calendar. Le fuseau horaire GMT a 0 décalage (pas vraiment important) et l'indicateur d'heure d'été réglé sur faux.

    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));
Michal
la source
N'oubliez pas de mettre à zéro la partie en millisecondes, sinon c'est une bonne réponse dans le contexte des anciennes classes, java.util.Dateetc. L'utilisation du hack pour définir le fuseau horaire sur GMT rend le code insensible aux effets de l'heure d'été.
Meno Hochschild
4

Le code suivant peut vous donner la sortie souhaitée:

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());
Vishal Ganjare
la source
3
Pouvez-vous expliquer exactement ce que fait votre code? La question semble se poser sur un delta temporel et, à première vue, votre code semble renvoyer un delta journalier?
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";
    }
}   
Parth Solanki
la source
3
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;
Bozho
la source
5
-1 C'est faux, sauf si les instances de Date sont dérivées des heures UTC. Voir la réponse de Jon Skeet.
sleske
5
@sleske vous n'avez pas raison. Il a déjà perdu les informations de fuseau horaire en utilisant Date, donc cette comparaison est la meilleure qui puisse être réalisée compte tenu des circonstances.
Bozho
1
OK, je suppose que nous avons tous les deux raison. Il est vrai que cela dépend de l'origine de l'instance Date. Pourtant, c'est une erreur si courante qu'il convient de la mentionner.
sleske
Lorsque j'utilise votre solution, elle dit: Non-correspondance de type: impossible de convertir de long en int. Je pense que vous devriez également ajouter un casting ou est-ce que je manque quelque chose?
Ad Infinitum
3

La meilleure chose à faire est

(Date1-Date2)/86 400 000 

Ce nombre est le nombre de millisecondes dans une journée.

Une date-autre date vous donne la différence en millisecondes.

Recueillez la réponse dans une double variable.

Revanth Kumar
la source
Oui pourquoi pas? Je ne comprends pas le point de la question à certains égards: OP a une différence en ms ... et il y a un certain nombre de ms par jour (OK avec certains ajustements astronomiques une fois dans une lune bleue, mais l'OP ne fonctionne pas ne dis pas qu'il doit être aussi précis que les astronomes en ont besoin ...)
Mike Rodent
3

Voici une solution Java 7 correcte dans O (1) sans aucune dépendance.

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;
}
suxumuxu
la source
2

C'est probablement la façon la plus simple de le faire - c'est peut-être parce que je code en Java (avec ses bibliothèques de date et d'heure certes maladroites) depuis un certain temps maintenant, mais ce code me semble "simple et agréable"!

Êtes-vous satisfait du retour du résultat en millisecondes, ou est-ce une partie de votre question que vous préféreriez qu'il soit retourné dans un autre format?

Andrzej Doyle
la source
2

Ne pas utiliser l'API standard, non. Vous pouvez lancer la vôtre en faisant quelque chose comme ceci:

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

Ou vous pouvez utiliser Joda :

DateTime a = ..., b = ...;
Duration d = new Duration(a, b);
Gustafc
la source
2

Juste pour répondre à la question initiale:

Mettez le code suivant dans une fonction comme 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;

Le plus important ici est de travailler avec des nombres longs lors de la multiplication et de la division. Et bien sûr, le décalage que Java applique dans son calcul des dates.

:)

MugiWara No Carlos
la source
2

Étant donné que la question est étiquetée avec 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
VasiliNovikov
la source
2

Après avoir parcouru toutes les autres réponses, pour conserver le type de date Java 7 mais être plus précis / standard avec l'approche diff de 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;
}
gène b.
la source
1

essaye ça:

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

vous pouvez éditer la chaîne dans le paramètre des méthodes parse ().

sabbibJAVA
la source