476 votes

Calculer la différence entre deux instances de date Java

Je utilise la classe java.util.Date de Java en Scala et je veux comparer un objet Date et l'heure actuelle. Je sais que je peux calculer la différence en utilisant getTime():

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

Cependant, cela me laisse simplement avec un long représentant les millisecondes. Y a-t-il un moyen plus simple, plus joli d'obtenir un delta de temps ?

12 votes

Pourquoi pas d'amour pour joda time? C'est pratiquement la meilleure option si vous devez gérer les dates en java.

9 votes

Veuillez vérifier ma solution élégante en 2 lignes, sans utiliser Joda et en donnant le résultat dans n'importe quelle unité de temps sur stackoverflow.com/a/10650881/82609

0 votes

596voto

Sebastien Lorber Points 9682

Simple diff (without lib)

/**
 * Obtenir une différence entre deux dates
 * @param date1 la date la plus ancienne
 * @param date2 la date la plus récente
 * @param timeUnit l'unité dans laquelle vous souhaitez la différence
 * @return la valeur de la différence, dans l'unité fournie
 */
public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
    long diffInMillies = date2.getTime() - date1.getTime();
    return timeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS);
}

Ensuite, vous pouvez appeler:

getDateDiff(date1, date2, TimeUnit.MINUTES);

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

TimeUnit est java.util.concurrent.TimeUnit, une énumération standard de Java allant de nanosecondes à jours.


Différence lisible par l'homme (sans lib)

public static Map computeDiff(Date date1, Date date2) {

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

    // créer la liste
    List units = new ArrayList(EnumSet.allOf(TimeUnit.class));
    Collections.reverse(units);

    // créer la carte résultat de TimeUnit et de différence
    Map result = new LinkedHashMap();
    long milliesRest = diffInMillies;

    for (TimeUnit unit : units) {

        // calculer la différence en millisecondes
        long diff = unit.convert(milliesRest, TimeUnit.MILLISECONDS);
        long diffInMilliesForUnit = unit.toMillis(diff);
        milliesRest = milliesRest - diffInMilliesForUnit;

        // mettre le résultat dans la carte
        result.put(unit, diff);
    }

    return result;
}

http://ideone.com/5dXeu6

La sortie ressemble à Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}, avec les unités ordonnées.

Il vous suffit de convertir cette carte en une chaîne conviviale pour l'utilisateur.


Avertissement

Les extraits de code ci-dessus calculent une simple différence entre 2 instants. Cela peut poser 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 des dates sans heure, vous pouvez avoir un jour/heure manquante.

À mon avis, la différence de dates est quelque peu subjective, surtout en ce qui concerne les jours. Vous pouvez :

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

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

  • comptez le nombre de changements de jour, 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 la différence de dates sur les jours correspond au 1er cas

Avec JodaTime

Si vous utilisez JodaTime, vous pouvez obtenir la différence pour 2 instants (dates millisecondes supportées par ReadableInstant) avec :

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

Mais vous pouvez également obtenir la différence pour des dates/heure locales :

// retourne 4 en raison de l'année bissextile de 366 jours
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5), PeriodType.years()).getYears() 

// cette fois-ci elle renvoie 5
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5+1), PeriodType.years()).getYears() 

// Et vous pouvez également utiliser ces méthodes statiques
Years.yearsBetween(LocalDate.now(), LocalDate.now().plusDays(365*5)).getYears()

0 votes

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 dates en chaînes significatives.

0 votes

@SebastienLorber Y a-t-il un moyen dans TimeUnit de calculer la différence ainsi? "L'alarme est programmée pour dans 3 jours, 4 heures et 12 minutes à partir de maintenant".

0 votes

Brilliant contenu a vraiment sauvé beaucoup de mon temps. Appréciez votre aide.

215voto

notnoop Points 30218

Le JDK Date API est malheureusement très défaillante. Je vous 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 : Au fait, Joda a deux concepts : Interval pour représenter un intervalle de temps entre deux instants de temps (représentant le temps entre 8h et 10h), et une Duration qui représente une durée sans les bornes de temps réelles (par exemple, représenter deux heures !)

Si vous vous souciez uniquement des comparaisons de temps, la plupart des implémentations de Date (y compris celle de JDK) implémentent l'interface Comparable qui vous permet d'utiliser le Comparable.compareTo()

0 votes

Au fait - vous voulez dire Comparable.compareTo() , pas Comparable.compare() .

0 votes

Joda-Time a trois classes pour décrire un intervalle de temps de différentes manières : Interval, Duration et Period. Cette réponse correcte discute des deux premières. Voir ma réponse pour des informations sur Period.

0 votes

Java 8 a une nouvelle api de date et heure comme joda.

162voto

Michael Borgwardt Points 181658
int diffEnJours = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

Remarquez que cela fonctionne avec les dates UTC, donc la différence peut être décalée d'un jour si vous regardez les dates locales. Et pour obtenir un fonctionnement correct avec les dates locales, il faut adopter une approche complètement différente en raison de l'heure d'été.

6 votes

Cela ne fonctionne pas correctement sur Android en fait. Des erreurs d'arrondi existent. L'exemple du 19 au 21 mai indique 1 jour car il arrondit 1,99 à 1. Utilisez la fonction round avant de convertir en entier.

4 votes

Ceci est la meilleure et la plus simple réponse. Lors du calcul de la différence entre deux dates, les fuseaux horaires locaux s'annulent mutuellement ... de sorte que la réponse correcte (en double) est simplement donnée par ((double) (newer.getTime() - older.getTime()) / (86400.0 * 1000.0); ... en tant que double, vous avez également le jour fractionnaire qui peut facilement être converti en HH:MM:ss.

8 votes

@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 perturber le résultat.

54voto

Jon Skeet Points 692016

Vous devez définir votre problème de manière plus claire. Vous pourriez simplement prendre le nombre de millisecondes entre les deux objets Date et diviser par le nombre de millisecondes dans 24 heures, par exemple... mais:

  • Cela ne tiendra pas compte des fuseaux horaires - Date est toujours en UTC
  • Cela ne tiendra pas compte de l'heure d'été (où il peut y avoir des jours qui ne durent que 23 heures, par exemple)
  • Même en UTC, combien de jours y a-t-il entre le 16 août à 23h et le 18 août à 2h du matin? Ce n'est que 27 heures, cela signifie-t-il un jour? Ou devrait-il y avoir trois jours car cela couvre trois dates?

1 votes

Je pensais que java.util. Date n'était qu'un petit wrapper autour d'une représentation temporelle en millisecondes, interprétée dans le fuseau horaire local (par défaut). L'affichage d'une Date me donne une représentation dans le fuseau horaire local. Suis-je confus ici?

39voto

Adriano Bacha Points 485
Jours d = Days.daysBetween(startDate, endDate);
int jours = d.getDays();

https://www.joda.org/joda-time/faq.html#datediff

2 votes

Pour information, le projet Joda-Time est désormais en mode maintenance, l'équipe recommande la migration vers les classes java.time.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X