Java Duration
Représentez des durées temporelles (heures, minutes, secondes) en Java avec Duration.
Duration représente une longueur de temps mesurée en secondes et nanosecondes. "Deux heures." "Cinq cents millisecondes." "Quarante-cinq minutes." En interne, ce sont deux nombres — un long seconds et un int nanos — et chaque opération sur lui est de l'arithmétique entière. Il ne connaît pas les calendriers, les mois ni l'heure d'été ; si vous lui donnez 24 heures, cela signifie exactement 86 400 secondes, que ces 24 heures traversent ou non un changement d'heure d'été.
C'est le bon type pour : les mesures de temps, les délais d'attente, les nouvelles tentatives avec backoff exponentiel, "attendre au plus X secondes," tout ce dont la réponse est un intervalle de temps réel. Le type complémentaire pour les durées calendaires ("un mois," "deux ans") est Period, abordé dans le chapitre suivant.
Création
Trois groupes de fabriques :
Duration.ofNanos(500_000_000);
Duration.ofMillis(500);
Duration.ofSeconds(45);
Duration.ofSeconds(60, 500_000_000); // with nanos
Duration.ofMinutes(2);
Duration.ofHours(1);
Duration.ofDays(7); // exactly 7 * 24 hours
Duration.between(start, end); // from two Temporals
Duration.parse("PT1H30M"); // ISO-8601: PT[hours]H[minutes]M[seconds]SDuration.ofDays(n) est la fabrique que la plupart des gens utilisent et que la plupart comprennent mal. Elle produit exactement n * 24 * 3600 secondes. Lors d'un changement d'heure d'été, ce n'est pas la même chose que "le lendemain à la même heure d'horloge murale." Pour un "jour plus tard" de forme calendaire, LocalDate.plusDays(1) ou Period.ofDays(1) sont les bons outils.
Le format de chaîne est la durée ISO-8601 : PT1H30M45S représente une heure, trente minutes, quarante-cinq secondes. Le PT initial est obligatoire (P = Period, T = Time). Pour les composantes inférieures à la seconde, la forme est PT0.5S ou PT0.000000001S. Duration couvre tout ce qui est en dessous du jour ; les périodes (année, mois, jour) appartiennent à Period.
Arithmétique
d.plus(Duration.ofSeconds(15));
d.plusSeconds(60);
d.plusMinutes(5);
d.plusHours(2);
d.minus(Duration.ofMillis(100));
d.multipliedBy(3);
d.dividedBy(2);
d.negated(); // -d
d.abs();Chaque méthode retourne un nouveau Duration (le principe d'immutabilité hérité de LocalDate et au-delà).
Les accesseurs de conversion :
d.toNanos(); // long
d.toMillis(); // long; throws if out of long range
d.toSeconds(); // since Java 9
d.toMinutes();
d.toHours();
d.toDays(); // assumes 24h days
d.getSeconds(); // raw seconds component
d.getNano(); // raw nanos component (0-999_999_999)Les méthodes toX() vous donnent un seul long du total dans cette unité, tronqué. Les méthodes getX() vous donnent la décomposition brute. Ce sont deux choses différentes ; les confondre est le bug Duration le plus courant.
Duration d = Duration.ofSeconds(125);
d.toMinutes(); // 2 (125 / 60)
d.getSeconds(); // 125 (raw)Pour un formatage "X minutes Y secondes," utilisez les deux :
long mins = d.toMinutes();
long secs = d.minusMinutes(mins).getSeconds();
System.out.printf("%d:%02d%n", mins, secs); // 2:05Ou, depuis Java 9, les helpers de décomposition dédiés :
d.toHoursPart(); // hours within the duration (0-23-ish on positive durations)
d.toMinutesPart(); // minutes within the duration (0-59)
d.toSecondsPart(); // seconds within the duration (0-59)
d.toMillisPart(); // millis within the secondCe sont ceux que vous voulez pour "afficher 1h 23m 45s" sans faire vous-même l'arithmétique modulo.
Comparaison
d1.isZero(); // d == 0
d1.isNegative(); // d < 0
d1.compareTo(d2);
d1.equals(d2);Duration est Comparable<Duration>. L'ordre est signé — une durée négative est inférieure à zéro, qui est inférieur à une durée positive.
Distance entre deux Temporals
La fabrique Duration.between(start, end) est celle que vous utiliserez le plus :
Duration d = Duration.between(start, end); // works on Instant, LocalDateTime, ZonedDateTime, LocalTimeElle accepte toute paire de valeurs Temporal qui supportent les unités basées sur le temps. LocalDate (date seulement) ne le fait pas — Duration.between(date1, date2) lève une DateTimeException car une date n'a pas de composante horloge. Pour la distance calendaire, utilisez Period.between(date1, date2) ou ChronoUnit.DAYS.between(date1, date2).
La convention de signe : positif si end est après start, négatif sinon.
Ajout à d'autres temporals
Duration est un TemporalAmount, donc tout Temporal l'accepte via plus/minus :
Instant later = Instant.now().plus(Duration.ofMinutes(30));
LocalDateTime then = LocalDateTime.now().plus(Duration.ofHours(8));Ajouter un Duration à un LocalDate lève une exception — même raison que ci-dessus, pas de composante horloge. Le compilateur ne détecte pas cela ; l'appel échoue à l'exécution. Si vous vous retrouvez à vouloir le faire, vous vouliez presque certainement Period.
Un exemple concret : mesure du temps, formatage, backoff
Le programme ci-dessous mesure le temps écoulé d'un petit travail, l'affiche sous une forme lisible par un humain en utilisant les helpers toXxxPart, calcule un calendrier de backoff exponentiel, et démontre la frontière Duration vs Period en montrant à la fois Duration.between sur des Instants et Period.between sur des LocalDates pour la même étendue de temps conceptuelle.
Ce qu'il faut retenir de l'exécution :
- Le bloc
Thread.sleep(125)a été mesuré commePT0.125-something-S— la variabilité réelle dusleepest due aux aléas de la machine réelle.Duration.between(t0, t1)était le bon appel : deuxInstants, aucune zone requise, réponse exacte à la résolution de l'horloge système. - Les helpers
toXxxPart()ont fourni des entiers propres pour "la partie heures," "la partie minutes," "la partie secondes," "la partie millis." Sans eux, vous devriez faire vous-même l'arithmétique modulototal / 3600et(total % 3600) / 60. Utilisez-les chaque fois que vous devez formater une durée pour un humain. - La boucle de backoff exponentiel a mis à l'échelle la durée avec
multipliedBy(2)et a affiché chaque résultat. La forme de chaîne ISO-8601 (PT2S,PT4S,PT8S, ...) est ce queDuration.toStringaffiche ; elle est concise et non ambiguë, idéale pour les journaux. - Le bloc "1er janvier → 1er avril sous trois formes" a montré la frontière
DurationvsPeriod.Period.between(start, end)a retournéP3M— trois mois calendaires.Duration.betweensur les instants UTC équivalents a retourné un décompte en temps réel (90 jours). Les deux sont corrects ; ils répondent à des questions différentes. Choisissez celui dont le sens correspond à l'intention de votre code. - Le dernier bloc a essayé
Duration.between(LocalDate, LocalDate)et a obtenu uneDateTimeException. Le système de types sait qu'une date n'a pas de composante horloge, donc il refuse de calculer une durée basée sur l'horloge. La correction est soit (1) d'attacher des heures (startDate.atStartOfDay(zone)), soit (2) d'utiliserPeriod.betweensi un décompte calendaire est ce que vous vouliez réellement. L'exception est la bonne conception : des réponses silencieuses à cette question seraient trompeuses.
La suite
Duration est la longueur en secondes et nanosecondes. Le chapitre suivant, Java Period, est la longueur en années-mois-jours — la contrepartie de forme calendaire. Les deux ne se mélangent jamais : Duration ne connaît pas les mois, Period ne connaît pas les heures, et tout code qui gère les deux atteint l'un ou l'autre selon que la réponse doit suivre le calendrier ou l'horloge murale.