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:55
et 09/09/2014 19:46:45
). La capture d'écran suivante montre la sortie:
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 LocalDateTime
objets 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.
Period.between()
appliquer un arrondi?7:45:55
et l'heure de fin19:46:45
(ou7:46:45
PM). 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.LocalDateTime
n'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.LocalDateTime
donne 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 viaZoneId
à utiliserZonedDateTime
.Réponses:
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:
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.
la source
ChronoUnit
:) mais fait le travail "à la main".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 appelsChronoUnit#between()
et terminer.J'ai trouvé que la meilleure façon de le faire est avec ChronoUnit.
La documentation supplémentaire est ici: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html
la source
tempDateTime.until( toDateTime, ChronoUnit.YEARS)
parChronoUnit.YEARS.between(fromDate, toDate)
. Mais les lignes supplémentaires importantes commetempDateTime.plusYears( years )
etc. manquent complètement dans votre réponse, donc cela n'aide pas l'OP. L'algorithme complet compte!Voici un seul exemple utilisant Duration et TimeUnit pour obtenir le format 'hh: mm: ss'.
la source
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.Ça devrait être plus simple!
la source
TL; DR
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
LocalDateTimes
en 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é suivanteminutes < 60
, c'est-à-direhours < 24
, et ainsi de suite.Étant donné deux
LocalDateTimes
start
etend
, par exemplenous pouvons représenter l'intervalle de temps absolu entre les deux avec un -
Duration
peut-être en utilisantDuration.between(start, end)
. Mais la plus grande unité que nous pouvons extraire d'un jourDuration
est 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 celaDuration
avec une paire de (Period
,Duration
), où laPeriod
mesure la différence jusqu'à une précision de jours et laDuration
représente le reste:Maintenant, nous pouvons simplement utiliser les méthodes définies sur
Period
etDuration
pour extraire les unités individuelles:ou, en utilisant le format par défaut:
Remarque sur les années, les mois et les jours
Notez que, dans
java.time
la 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:la source
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
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:
La méthode ci-dessus peut être utilisée pour calculer la différence des valeurs locales de date et d'heure, par exemple:
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:
}
Tous les tests réussissent, que la valeur du premier LocalDateTime soit antérieure ou non à toutes les valeurs LocalTime.
la source
java.time.Period
où les utilisateurs peuvent appliquer / produire de tels signes mixtes en raison de la conception interne différente).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.
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 revient23 Hours
.Lorsque vous fournissez une liste d'unités, elle doit être triée par taille des unités (la plus grande en premier):
la source
Voici une réponse très simple à votre question. Ça marche.
la source
Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old
. Je ne pense pas que ce soit ce qui était souhaité.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:
la source
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:
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.
la source
toHours
,toMinutes
et destoSeconds
méthodes deDuration
. Depuis Java 9 encore plus detoMinutesPart()
ettoSecondsPart()
. 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.