Pourquoi ne puis-je pas obtenir une durée en minutes ou en heures en java.time?

De la classe Duration du nouvel API de date JSR 310 ( package java.time ) disponible dans Java 8 et versions ultérieures, le javadoc dit:

Cette classe modélise une quantité ou une quantité de temps en secondes et en nanosecondes. On peut y accéder en utilisant d’autres unités basées sur la durée, telles que les minutes et les heures . En outre, l’unité DAYS peut être utilisée et est traitée exactement comme 24 heures, ignorant ainsi les effets de l’heure d’été.

Alors, pourquoi le code suivant plante-t-il?

 Duration duration = Duration.ofSeconds(3000); System.out.println(duration.get(ChronoUnit.MINUTES)); 

Cela déclenche une UnsupportedTemporalTypeException :

 java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Minutes at java.time.Duration.get(Duration.java:537) 

Alors, comment est-il recommandé d’extraire les minutes et les heures d’un object de durée? Devons-nous faire le calcul nous-mêmes à partir du nombre de secondes? Pourquoi a-t-il été mis en œuvre de cette façon?

“Pourquoi a-t-il été mis en œuvre de cette façon?”

D’autres réponses concernent les méthodes toXxx() qui permettent d’interroger les heures / minutes. Je vais essayer de comprendre pourquoi.

L’interface TemporalAmount et la méthode get(TemporalUnit) été ajoutées assez tard dans le processus. Personnellement, je n’étais pas entièrement convaincu que nous avions suffisamment de preuves de la bonne façon de travailler sur le design dans ce domaine, mais que nous avions un peu de mal à append TemporalAmount . Je crois que ce faisant, nous avons légèrement confondu l’API.

Avec le recul, je pense que TemporalAmount contient les bonnes méthodes, mais je pense que get(TemporalUnit) devrait avoir un nom de méthode différent. La raison en est que get(TemporalUnit) est essentiellement une méthode de niveau cadre – elle n’est pas conçue pour une utilisation quotidienne. Malheureusement, le nom de la méthode get n’implique pas cela, ce qui entraîne des bogues comme l’appel de get(ChronoUnit.MINUTES) à Duration .

Donc, la manière de penser à get(TemporalUnit) est d’imaginer un cadre de bas niveau affichant la quantité sous la forme d’une MapDuration est une Map de taille deux avec les clés SECONDS et NANOS .

De la même manière, Period est considérée à partir des frameworks de bas niveau comme une Map de taille trois – DAYS , MONTHS et YEARS (ce qui a heureusement moins de risques d’erreurs).

Dans l’ensemble, le meilleur conseil pour le code d’application est d’ignorer la méthode get(TemporalUnit) . Utilisez getSeconds() , getNano() , toHours() et toMinutes() .

Enfin, une façon d’obtenir “hh: mm: ss” d’une Duration est de faire:

 LocalTime.MIDNIGHT.plus(duration).format(DateTimeFormatter.ofPattern("HH:mm:ss")) 

Pas beau du tout, mais ça marche pour des durées inférieures à une journée.

Nouveau to…Part Méthodes de pièces en Java 9

Le problème JDK-8142936 est désormais implémenté dans Java 9, en ajoutant les méthodes suivantes pour accéder à chaque partie d’une Duration .

  • toDaysPart
  • toHoursPart
  • toMinutesPart
  • toSecondsPart
  • toMillisPart
  • toNanosPart

La documentation dit:

Cela renvoie une valeur pour chacune des deux unités sockets en charge, SECONDS et NANOS. Toutes les autres unités lancent une exception.

Alors, mieux vaut répondre – c’est comme ça qu’ils l’ont conçu.

Vous pouvez utiliser certaines des autres méthodes pour l’obtenir en heures :

 long hours = duration.toHours(); 

ou minutes :

 long minutes = duration.toMinutes(); 

Je voudrais append à la réponse de bigt (+1) qui indique les méthodes de conversion les plus utiles, les toMinutes et les autres. La spécification de la durée indique:

Cette classe modélise une quantité ou une quantité de temps en secondes et en nanosecondes. […]

La plage d’une durée nécessite le stockage d’un nombre supérieur à un long. Pour ce faire, la classe stocke un long représentant les secondes et un int représentant les nanosecondes de seconde, qui sera toujours compris entre 0 et 999 999 999.

Il existe une variété de méthodes de getSeconds telles que getSeconds , getNano et get(TemporalUnit) . Étant donné qu’une durée est représentée par une paire (secondes, nanos), il est clair que get(TemporalUnit) est limité aux secondes et nanos. Ces méthodes getter extraient les données directement de l’instance de durée et sont sans perte.

En revanche, il existe une variété de méthodes, y compris toDays , toHours , toMillis toMinutes et toNanos qui effectuent des conversions sur la valeur de durée. Ces conversions comportent des pertes en ce qu’elles impliquent une troncature des données ou une exception si la valeur de la durée ne peut pas être représentée dans le format demandé.

Il est clair que les méthodes get extraient les données sans conversion et que les méthodes to exécutent des conversions.

Pour obtenir les composants heure / minute / seconde de manière “normalisée”, vous devez les calculer manuellement – le code ci-dessous est essentiellement copié à partir de la méthode Duration#toSsortingng :

 Duration duration = Duration.ofSeconds(3000); long hours = duration.toHours(); int minutes = (int) ((duration.getSeconds() % (60 * 60)) / 60); int seconds = (int) (duration.getSeconds() % 60); System.out.println(hours + ":" + minutes + ":" + seconds); 

En dessous du code j’ai eu cette sortie de durée:

1 jour, 2 heures, 5 minutes

exemple de code:

 private Ssortingng getDurationAsSsortingng(Duration duration) { SsortingngBuilder durationAsSsortingngBuilder = new SsortingngBuilder(); if (duration.toDays() > 0) { Ssortingng postfix = duration.toDays() == 1 ? "" : "s"; durationAsSsortingngBuilder.append(duration.toDays() + " day"); durationAsSsortingngBuilder.append(postfix); } duration = duration.minusDays(duration.toDays()); long hours = duration.toHours(); if (hours > 0) { Ssortingng prefix = Utils.isEmpty(durationAsSsortingngBuilder.toSsortingng()) ? "" : ", "; Ssortingng postfix = hours == 1 ? "" : "s"; durationAsSsortingngBuilder.append(prefix); durationAsSsortingngBuilder.append(hours + " hour"); durationAsSsortingngBuilder.append(postfix); } duration = duration.minusHours(duration.toHours()); long minutes = duration.toMinutes(); if (minutes > 0) { Ssortingng prefix = Utils.isEmpty(durationAsSsortingngBuilder.toSsortingng()) ? "" : ", "; Ssortingng postfix = minutes == 1 ? "" : "s"; durationAsSsortingngBuilder.append(prefix); durationAsSsortingngBuilder.append(minutes + " minute"); durationAsSsortingngBuilder.append(postfix); } return durationAsSsortingngBuilder.toSsortingng(); } 

Explication :

En utilisant l’interface Durée, vous pouvez facilement trouver l’affichage exact des chaînes souhaité. il suffit de réduire la plus grande unité temporelle de la durée actuelle.

par exemple:

  1. calculer les jours
  2. réduire les jours de la durée
  3. calculer les heures
  4. réduire les heures de la durée, etc. jusqu’à ce que la durée soit égale à 0