Java 8: différence entre deux LocalDateTime dans plusieurs unités

266

J'essaie de calculer la différence entre deux LocalDateTime.

La sortie doit être au format y years m months d days h hours m minutes s seconds. Voici ce que j'ai écrit:

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;

public class Main {

    static final int MINUTES_PER_HOUR = 60;
    static final int SECONDS_PER_MINUTE = 60;
    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;

    public static void main(String[] args) {
        LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
        LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

        Period period = getPeriod(fromDateTime, toDateTime);
        long time[] = getTime(fromDateTime, toDateTime);

        System.out.println(period.getYears() + " years " + 
                period.getMonths() + " months " + 
                period.getDays() + " days " +
                time[0] + " hours " +
                time[1] + " minutes " +
                time[2] + " seconds.");


    }

    private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
        return Period.between(dob.toLocalDate(), now.toLocalDate());
    }

    private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
        LocalDateTime today = LocalDateTime.of(now.getYear(),
                now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
        Duration duration = Duration.between(today, now);

        long seconds = duration.getSeconds();

        long hours = seconds / SECONDS_PER_HOUR;
        long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
        long secs = (seconds % SECONDS_PER_MINUTE);

        return new long[]{hours, minutes, secs};
    }
}

La sortie que j'obtiens est 29 years 8 months 24 days 12 hours 0 minutes 50 seconds. J'ai vérifié mon résultat sur ce site (avec les valeurs 12/16/1984 07:45:55et 09/09/2014 19:46:45). La capture d'écran suivante montre la sortie:

Convertisseur d'époque

Je suis presque sûr que les champs après la valeur du mois ne correspondent pas à mon code. Toute suggestion serait très utile.

Mettre à jour

J'ai testé mon résultat sur un autre site Web et le résultat que j'ai obtenu est différent. La voici: calculer la durée entre deux dates (résultat: 29 ans, 8 mois, 24 jours, 12 heures, 0 minute et 50 secondes).

Mettre à jour

Comme j'ai obtenu deux résultats différents sur deux sites différents, je me demande si l'algorithme de mon calcul est légitime ou non. Si j'utilise les deux LocalDateTimeobjets suivants:

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

Ensuite, la sortie arrive: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.

De ce lien, il devrait être 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds. Donc, l'algorithme doit également gérer les nombres négatifs.

Notez que la question n'est pas de savoir quel site m'a donné quel résultat, j'ai besoin de connaître le bon algorithme et d'avoir les bons résultats.

Tapas Bose
la source
Juste une supposition, mais pourrait Period.between()appliquer un arrondi?
Thomas
3
Je viens de revoir le code et il semble que le site Web soit incorrect (essayez de vous calculer). Si vous omettez la date, c'est-à-dire les différences dans l'année, le mois et le jour, vous obtiendrez l'heure de début 7:45:55et l'heure de fin 19:46:45(ou 7:46:45PM). La différence entre ces deux temps est donc de 12 heures, 0 minute et 50 secondes et jamais de 23 heures, 34 minutes et 12 secondes. Votre calcul semble donc être correct, du moins sur la partie temps.
Thomas
1
Phénomène intéressant sur ce site: ajouter 10 ans à la date de début et la différence d'heures passe de 23 à 8 - sûrement un signe de bug.
Thomas
8
Notez qu'étant donné qu'il LocalDateTimen'y a pas de fuseau horaire, il se peut qu'il n'y ait pas de réponse unique. Même si vous supposez que les fuseaux horaires de début et de fin sont les mêmes, dans certaines zones, comme le 2014-09-09, l'heure d'été ou l'heure d'été sera la même dans d'autres. Cela pourrait gâcher les choses d'une heure. Donc, calculer la différence avec la seconde n'a de sens que si cela est résolu.
Stuart marque le
2
Comprenez-vous que l'utilisation LocalDateTimedonne des résultats irréalistes, car cette classe n'a délibérément aucun concept de fuseau horaire ou de décalage par rapport à l'UTC? Pour des valeurs réalistes, attribuez un fuseau horaire via ZoneIdà utiliser ZonedDateTime.
Basil Bourque

Réponses:

163

Malheureusement, il ne semble pas y avoir de classe de période qui couvre également le temps, vous devrez donc peut-être faire les calculs vous-même.

Heureusement, les classes de date et d'heure ont beaucoup de méthodes utilitaires qui simplifient cela dans une certaine mesure. Voici un moyen de calculer la différence mais pas nécessairement la plus rapide:

LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);

LocalDateTime tempDateTime = LocalDateTime.from( fromDateTime );

long years = tempDateTime.until( toDateTime, ChronoUnit.YEARS );
tempDateTime = tempDateTime.plusYears( years );

long months = tempDateTime.until( toDateTime, ChronoUnit.MONTHS );
tempDateTime = tempDateTime.plusMonths( months );

long days = tempDateTime.until( toDateTime, ChronoUnit.DAYS );
tempDateTime = tempDateTime.plusDays( days );


long hours = tempDateTime.until( toDateTime, ChronoUnit.HOURS );
tempDateTime = tempDateTime.plusHours( hours );

long minutes = tempDateTime.until( toDateTime, ChronoUnit.MINUTES );
tempDateTime = tempDateTime.plusMinutes( minutes );

long seconds = tempDateTime.until( toDateTime, ChronoUnit.SECONDS );

System.out.println( years + " years " + 
        months + " months " + 
        days + " days " +
        hours + " hours " +
        minutes + " minutes " +
        seconds + " seconds.");

//prints: 29 years 8 months 24 days 22 hours 54 minutes 50 seconds.

L'idée de base est la suivante: créer une date de début temporaire et terminer les années complètes. Ajustez ensuite cette date en fonction du nombre d'années afin que la date de début soit inférieure à un an à compter de la fin. Répétez cette opération pour chaque unité de temps dans l'ordre décroissant.

Enfin un avertissement : je n'ai pas pris en compte différents fuseaux horaires (les deux dates doivent être dans le même fuseau horaire) et je n'ai pas non plus testé / vérifié comment l'heure d'été ou d'autres changements dans un calendrier (comme les changements de fuseau horaire aux Samoa) affecter ce calcul. Utilisez donc avec précaution.

Thomas
la source
1
Vous avez la même idée de base, donc mon vote positif, mais essayez d'utiliser la même entrée sinon le résultat différent est déroutant.
Meno Hochschild
@MenoHochschild il est la même entrée, vient de prendre de la mise à jour où l'OP a des problèmes avec des temps négatifs. ;)
Thomas
1
Bon algorithme, mais mauvais type (voir la clause de non-responsabilité de Thomas). Avant de faire votre calcul, vous devez convertir vos variables LocalDateTime en ZonedDateTime en utilisant le fuseau horaire par défaut par exemple (ou tout fuseau horaire dont vous avez besoin): ZonedDateTime fromZonedDateTime = fromDateTime.atZone (ZoneId.systemDefault ());
Tristan
2
@Thomas Votre exemple utilise également Java 8 - et la question est marquée comme java-8. En fait, votre exemple utilise même ChronoUnit:) mais fait le travail "à la main".
Eugene Beresovsky
3
@EugeneBeresovsky oh oui, vous avez raison. Cela a totalement manqué;) - En plus de cela, vous devrez toujours soustraire les unités les plus grandes de l'intervalle car, par exemple long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);, retournerait un nombre supérieur à 59 pour tout intervalle d'au moins 1 heure - et ce n'est pas ce que l'OP veut. En tenant compte de cela, vous ne pourriez pas simplement faire 6 appels ChronoUnit#between()et terminer.
Thomas
503

J'ai trouvé que la meilleure façon de le faire est avec ChronoUnit.

long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);
long hours = ChronoUnit.HOURS.between(fromDate, toDate);

La documentation supplémentaire est ici: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html

satnam
la source
8
Je ne vois pas de réelle amélioration. Par rapport à la réponse de Thomas acceptée, vous venez de remplacer tempDateTime.until( toDateTime, ChronoUnit.YEARS)par ChronoUnit.YEARS.between(fromDate, toDate). Mais les lignes supplémentaires importantes comme tempDateTime.plusYears( years )etc. manquent complètement dans votre réponse, donc cela n'aide pas l'OP. L'algorithme complet compte!
Meno Hochschild
9
J'aime mieux cela car il est plus succinct et plus lisible. C'est le meilleur moyen de trouver la différence entre deux dates.
Somaiah Kumbera
7
@SomaiahKumbera Non, vous manquez complètement le point critique. L'OP ne veut pas d'une durée dans une seule unité mais dans plusieurs unités , et donc cette réponse n'est pas du tout une vraie réponse. La préoccupation du PO n'est tout simplement pas prise en compte. Merci de bien vouloir relire la question. (Beaucoup d'électeurs semblent avoir mal compris la question).
Meno Hochschild
126
@MenoHochschild, je pense que vous êtes en fait celui qui manque le point critique. Le PO a obtenu sa réponse il y a plus d'un an. Les 36 000 personnes qui consultent cette question ne se soucient pas de la question spécifique du PO. Ils ont été dirigés ici par Google et ma réponse leur a fourni ce qu'ils cherchaient - une solution propre et simple pour faire la différence entre deux dates.
samedi
10
J'avais besoin de la différence en secondes entre deux dates et j'ai commencé à implémenter ma propre solution. Peu de temps cela semble complexe et je me suis lancé sur google. La réponse de satnam ne répond peut-être pas à la question OP, mais elle m'a certainement beaucoup aidé et je parie que beaucoup d'autres comme moi.
Julian
43

Voici un seul exemple utilisant Duration et TimeUnit pour obtenir le format 'hh: mm: ss'.

Duration dur = Duration.between(localDateTimeIni, localDateTimeEnd);
long millis = dur.toMillis();

String.format("%02d:%02d:%02d", 
        TimeUnit.MILLISECONDS.toHours(millis),
        TimeUnit.MILLISECONDS.toMinutes(millis) - 
        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
        TimeUnit.MILLISECONDS.toSeconds(millis) - 
        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
Batista junior
la source
2
Il est en fait possible de le faire comme ceci: String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());. Les méthodes de partie vous donnent les bons nombres pour construire une chaîne. Je pense que c'est plus lisible.
Daantie
Note complémentaire à mon commentaire précédent: les méthodes de pièce ne sont disponibles qu'à partir de JDK 9 et plus.
Daantie
40

Ça devrait être plus simple!

Duration.between(startLocalDateTime, endLocalDateTime).toMillis();
Zon
la source
1
Je crois que c'est en fait la solution sémantiquement correcte à partir de Java 8. Et avant cette version, JodaTime fait de même.
Vrakfall
9

TL; DR

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

puis utiliser les méthodes period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart().


Réponse élargie

Je vais répondre à la question d'origine, c'est-à-dire comment obtenir la différence de temps entre deux LocalDateTimesen années, mois, jours, heures et minutes, de sorte que la "somme" (voir note ci-dessous) de toutes les valeurs pour les différentes unités soit égale au total différence temporelle, et telle que la valeur dans chaque unité est plus petite que la plus grande unité suivante minutes < 60, c'est-à-dire hours < 24, et ainsi de suite.

Étant donné deux LocalDateTimes startet end, par exemple

LocalDateTime start = LocalDateTime.of(2019, 11, 29, 17, 15);
LocalDateTime end = LocalDateTime.of(2020, 11, 30, 18, 44);

nous pouvons représenter l'intervalle de temps absolu entre les deux avec un - Durationpeut-être en utilisant Duration.between(start, end). Mais la plus grande unité que nous pouvons extraire d'un jour Durationest les jours (en tant qu'unité temporelle équivalente à 24h) - voir la note ci-dessous pour une explication. Pour utiliser des unités plus grandes (mois, années), nous pouvons représenter cela Durationavec une paire de ( Period, Duration), où la Periodmesure la différence jusqu'à une précision de jours et la Durationreprésente le reste:

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

Maintenant, nous pouvons simplement utiliser les méthodes définies sur Periodet Durationpour extraire les unités individuelles:

System.out.printf("%d years, %d months, %d days, %d hours, %d minutes, %d seconds",
        period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(),
        duration.toMinutesPart(), duration.toSecondsPart());
1 years, 0 months, 1 days, 1 hours, 29 minutes, 0 seconds

ou, en utilisant le format par défaut:

System.out.println(period + " + " + duration);
P1Y1D + PT1H29M

Remarque sur les années, les mois et les jours

Notez que, dans java.timela conception de, les "unités" comme "mois" ou "année" ne représentent pas une valeur temporelle absolue fixe - elles dépendent de la date et du calendrier, comme l'illustre l'exemple suivant:

LocalDateTime
        start1 = LocalDateTime.of(2020, 1, 1, 0, 0),
        end1 = LocalDateTime.of(2021, 1, 1, 0, 0),
        start2 = LocalDateTime.of(2021, 1, 1, 0, 0),
        end2 = LocalDateTime.of(2022, 1, 1, 0, 0);
System.out.println(Period.between(start1.toLocalDate(), end1.toLocalDate()));
System.out.println(Duration.between(start1, end1).toDays());
System.out.println(Period.between(start2.toLocalDate(), end2.toLocalDate()));
System.out.println(Duration.between(start2, end2).toDays());
P1Y
366
P1Y
365
Anakhand
la source
5

Il y a un problème pour le code Tapas Bose et le code Thomas. Si la différence de temps est négative, le tableau obtient les valeurs négatives. Par exemple si

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);

il renvoie 0 ans 0 mois 1 jours -1 heures 0 minutes 0 secondes.

Je pense que la bonne sortie est: 0 ans 0 mois 0 jours 23 heures 0 minutes 0 secondes.

Je propose de séparer les instances LocalDateTime sur les instances LocalDate et LocalTime. Après cela, nous pouvons obtenir les instances de période et de durée Java 8. L'instance de durée est séparée en nombre de jours et en valeur horaire (<24h) avec correction ultérieure de la valeur de période. Lorsque la deuxième valeur LocalTime est antérieure à la première valeur LocalTime, il est nécessaire de réduire la période d'un jour.

Voici ma façon de calculer la différence LocalDateTime:

private void getChronoUnitForSecondAfterFirst(LocalDateTime firstLocalDateTime, LocalDateTime secondLocalDateTime, long[] chronoUnits) {
    /*Separate LocaldateTime on LocalDate and LocalTime*/
    LocalDate firstLocalDate = firstLocalDateTime.toLocalDate();
    LocalTime firstLocalTime = firstLocalDateTime.toLocalTime();

    LocalDate secondLocalDate = secondLocalDateTime.toLocalDate();
    LocalTime secondLocalTime = secondLocalDateTime.toLocalTime();

    /*Calculate the time difference*/
    Duration duration = Duration.between(firstLocalDateTime, secondLocalDateTime);
    long durationDays = duration.toDays();
    Duration throughoutTheDayDuration = duration.minusDays(durationDays);
    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Duration is: " + duration + " this is " + durationDays
            + " days and " + throughoutTheDayDuration + " time.");

    Period period = Period.between(firstLocalDate, secondLocalDate);

    /*Correct the date difference*/
    if (secondLocalTime.isBefore(firstLocalTime)) {
        period = period.minusDays(1);
        Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
                "minus 1 day");
    }

    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Period between " + firstLocalDateTime + " and "
            + secondLocalDateTime + " is: " + period + " and duration is: "
            + throughoutTheDayDuration
            + "\n-----------------------------------------------------------------");

    /*Calculate chrono unit values and  write it in array*/
    chronoUnits[0] = period.getYears();
    chronoUnits[1] = period.getMonths();
    chronoUnits[2] = period.getDays();
    chronoUnits[3] = throughoutTheDayDuration.toHours();
    chronoUnits[4] = throughoutTheDayDuration.toMinutes() % 60;
    chronoUnits[5] = throughoutTheDayDuration.getSeconds() % 60;
}

La méthode ci-dessus peut être utilisée pour calculer la différence des valeurs locales de date et d'heure, par exemple:

public long[] getChronoUnits(String firstLocalDateTimeString, String secondLocalDateTimeString) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    LocalDateTime firstLocalDateTime = LocalDateTime.parse(firstLocalDateTimeString, formatter);
    LocalDateTime secondLocalDateTime = LocalDateTime.parse(secondLocalDateTimeString, formatter);

    long[] chronoUnits = new long[6];
    if (secondLocalDateTime.isAfter(firstLocalDateTime)) {
        getChronoUnitForSecondAfterFirst(firstLocalDateTime, secondLocalDateTime, chronoUnits);
    } else {
        getChronoUnitForSecondAfterFirst(secondLocalDateTime, firstLocalDateTime, chronoUnits);
    }
    return chronoUnits;
}

Il est pratique d'écrire un test unitaire pour la méthode ci-dessus (les deux sont des membres de la classe PeriodDuration). Voici le code:

@RunWith(Parameterized.class)
public class PeriodDurationTest {

private final String firstLocalDateTimeString;
private final String secondLocalDateTimeString;
private final long[] chronoUnits;

public PeriodDurationTest(String firstLocalDateTimeString, String secondLocalDateTimeString, long[] chronoUnits) {
    this.firstLocalDateTimeString = firstLocalDateTimeString;
    this.secondLocalDateTimeString = secondLocalDateTimeString;
    this.chronoUnits = chronoUnits;
}

@Parameters
public static Collection<Object[]> periodValues() {
    long[] chronoUnits0 = {0, 0, 0, 0, 0, 0};
    long[] chronoUnits1 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits2 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits3 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits4 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits5 = {0, 0, 1, 23, 0, 0};
    long[] chronoUnits6 = {29, 8, 24, 12, 0, 50};
    long[] chronoUnits7 = {29, 8, 24, 12, 0, 50};
    return Arrays.asList(new Object[][]{
        {"2015-09-09 21:46:44", "2015-09-09 21:46:44", chronoUnits0},
        {"2015-09-09 21:46:44", "2015-09-09 22:46:44", chronoUnits1},
        {"2015-09-09 21:46:44", "2015-09-10 20:46:44", chronoUnits2},
        {"2015-09-09 21:46:44", "2015-09-09 20:46:44", chronoUnits3},
        {"2015-09-10 20:46:44", "2015-09-09 21:46:44", chronoUnits4},
        {"2015-09-11 20:46:44", "2015-09-09 21:46:44", chronoUnits5},
        {"1984-12-16 07:45:55", "2014-09-09 19:46:45", chronoUnits6},
        {"2014-09-09 19:46:45", "1984-12-16 07:45:55", chronoUnits6}
    });
}

@Test
public void testGetChronoUnits() {
    PeriodDuration instance = new PeriodDuration();
    long[] expResult = this.chronoUnits;
    long[] result = instance.getChronoUnits(this.firstLocalDateTimeString, this.secondLocalDateTimeString);
    assertArrayEquals(expResult, result);
}

}

Tous les tests réussissent, que la valeur du premier LocalDateTime soit antérieure ou non à toutes les valeurs LocalTime.

Gennady Kolomoets
la source
Je ne peux pas reproduire votre déclaration selon laquelle le code Thomas utilisant votre entrée ci-dessus produit des signes mixtes. Ma sortie est: "0 ans 0 mois 0 jours 23 heures 0 minutes 0 secondes.". Et je viens de tester.
Meno Hochschild
Merci pour le commentaire. J'ai bien testé le code Thomas, en effet, il fonctionne correctement! La magie est effectuée par LocalDateTime jusqu'à la méthode de correction des unités chrono. Des valeurs négatives dans le code Thomas apparaissent si le premier DateTime est postérieur au second. Mais cela peut être facilement corrigé, par exemple, comme je l'ai fait dans le code ci-dessus. Merci encore.
Gennady Kolomoets
Eh bien, le code Thomas et ma bibliothèque Time4J utilisant le même algorithme pour le calcul des durées peuvent produire des signes négatifs mais uniquement pour toute la durée. Voilà le point crucial! Le signe se rapporte à la durée entière et décrit donc si le début est postérieur à la fin et n'est jamais lié à des composants de durée unique. Les signes mixtes ne sont pas possibles ici et empêcheraient une telle interprétation du début à la fin (le contre-exemple est Joda-Time-period ou java.time.Periodoù les utilisateurs peuvent appliquer / produire de tels signes mixtes en raison de la conception interne différente).
Meno Hochschild
5

Et la version de @Thomas dans Groovy avec prend les unités souhaitées dans une liste au lieu de coder en dur les valeurs. Cette implémentation (qui peut facilement être portée sur Java - j'ai rendu la déclaration de fonction explicite) rend l'approche Thomas plus réutilisable.

def fromDateTime = LocalDateTime.of(1968, 6, 14, 0, 13, 0)
def toDateTime = LocalDateTime.now()
def listOfUnits = [
    ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS,
    ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS,
    ChronoUnit.MILLIS]

println calcDurationInTextualForm(listOfUnits, fromDateTime, toDateTime)    

String calcDurationInTextualForm(List<ChronoUnit> listOfUnits, LocalDateTime ts, LocalDateTime to)
{
    def result = []

    listOfUnits.each { chronoUnit ->
        long amount = ts.until(to, chronoUnit)
        ts = ts.plus(amount, chronoUnit)

        if (amount) {
            result << "$amount ${chronoUnit.toString()}"
        }
    }

    result.join(', ')
}

Au moment d'écrire ces lignes, le code ci-dessus revient 47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis. Et, pour l'entrée @Gennady Kolomoets, le code revient 23 Hours.

Lorsque vous fournissez une liste d'unités, elle doit être triée par taille des unités (la plus grande en premier):

def listOfUnits = [ChronoUnit.WEEKS, ChronoUnit.DAYS, ChronoUnit.HOURS]
// returns 2495 Weeks, 3 Days, 8 Hours
ChrLipp
la source
4

Voici une réponse très simple à votre question. Ça marche.

import java.time.*;
import java.util.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class MyClass {
public static void main(String args[]) {
    DateTimeFormatter T = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
    Scanner h = new Scanner(System.in);

    System.out.print("Enter date of birth[dd/mm/yyyy hh:mm]: ");
    String b = h.nextLine();

    LocalDateTime bd = LocalDateTime.parse(b,T);
    LocalDateTime cd = LocalDateTime.now();

    long minutes = ChronoUnit.MINUTES.between(bd, cd);
    long hours = ChronoUnit.HOURS.between(bd, cd);

    System.out.print("Age is: "+hours+ " hours, or " +minutes+ " minutes old");
}
}
SavedBeau
la source
1
Je dois mentionner que ce n'est pas exact. essayez avec ça. il indique 1 minute de différence. LocalDateTime bd = LocalDateTime.of (2019, 11, 26, 15, 03, 55); LocalDateTime cd = LocalDateTime.of (2019, 11, 26, 15, 04, 45);
Mark Amabile
Je suis entré une heure hier soir et j'ai réussi Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old. Je ne pense pas que ce soit ce qui était souhaité.
Ole VV
@ OleV.V. Correction de ce problème
SavedBeau
1

Joda-Time

Étant donné que de nombreuses réponses nécessitaient une prise en charge de l' API 26 et que mon API minimale était de 23, je l'ai résolu par le code ci-dessous:

import org.joda.time.Days

LocalDate startDate = Something
LocalDate endDate = Something
// The difference would be exclusive of both dates, 
// so in most of use cases we may need to increment it by 1
Days.daysBetween(startDate, endDate).days
Kushal
la source
1
Le projet Joda-Time est en mode maintenance, son créateur Stephen Colebourne ayant ensuite créé les classes java.time définies dans JSR 310. La plupart des fonctionnalités de java.time sont rétroportées vers Java 6 et 7 dans ThreeTen- Projet de backport . Plus adapté pour les premiers Android dans le projet ThreeTenABP .
Basil Bourque
1

Après plus de cinq ans, je réponds à ma question. Je pense que le problème avec une durée négative peut être résolu par une simple correction:

LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);

Period period = Period.between(fromDateTime.toLocalDate(), toDateTime.toLocalDate());
Duration duration = Duration.between(fromDateTime.toLocalTime(), toDateTime.toLocalTime());

if (duration.isNegative()) {
    period = period.minusDays(1);
    duration = duration.plusDays(1);
}
long seconds = duration.getSeconds();
long hours = seconds / SECONDS_PER_HOUR;
long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
long secs = (seconds % SECONDS_PER_MINUTE);
long time[] = {hours, minutes, secs};
System.out.println(period.getYears() + " years "
            + period.getMonths() + " months "
            + period.getDays() + " days "
            + time[0] + " hours "
            + time[1] + " minutes "
            + time[2] + " seconds.");

Remarque: Le site https://www.epochconverter.com/date-difference calcule désormais correctement le décalage horaire.

Merci à tous pour votre discussion et vos suggestions.

Gennady Kolomoets
la source
Merci d'avoir répondu. Pour les heures et les petits, vous pouvez bénéficier de la toHours, toMinuteset des toSecondsméthodes de Duration. Depuis Java 9 encore plus de toMinutesPart()et toSecondsPart(). Et je ne vois pas l'intérêt de regrouper les heures, les minutes et les secondes dans un tableau uniquement pour les supprimer à nouveau. Généralement une bonne réponse, cependant.
Ole VV
Après plus de cinq ans, je réponds à ma question. La question a été publiée à partir d'un compte avec un nom, un titre et un emplacement différents, il ne semble pas y avoir beaucoup de ressemblance? Non pas que cela ait une importance, je me demande simplement.
Ole VV
"Après plus de cinq ans je réponds à ma question" Je suppose que j'étais l'OP :)
Tapas Bose