W3docs

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]S

Duration.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:05

Ou, 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 second

Ce 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, LocalTime

Elle accepte toute paire de valeurs Temporal qui supportent les unités basées sur le temps. LocalDate (date seulement) ne le fait pasDuration.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.

java— editable, runs on the server

Ce qu'il faut retenir de l'exécution :

  • Le bloc Thread.sleep(125) a été mesuré comme PT0.125-something-S — la variabilité réelle du sleep est due aux aléas de la machine réelle. Duration.between(t0, t1) était le bon appel : deux Instants, 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 modulo total / 3600 et (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 que Duration.toString affiche ; 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 Duration vs Period. Period.between(start, end) a retourné P3M — trois mois calendaires. Duration.between sur 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 une DateTimeException. 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'utiliser Period.between si 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.

Exercice

Pratique
Vous voulez relancer une requête HTTP après 'un jour', c'est-à-dire '24 heures à partir de maintenant, sans tenir compte de l'heure d'été.' Quel type et quel appel font cela ?
Vous voulez relancer une requête HTTP après 'un jour', c'est-à-dire '24 heures à partir de maintenant, sans tenir compte de l'heure d'été.' Quel type et quel appel font cela ?
Was this page helpful?