web-dev-qa-db-fra.com

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

Parmi les Duration class de la nouvelle JSR 310 date API ( package Java.time ) disponible dans Java 8 et versions ultérieures, le javadoc indique:

Cette classe modélise une quantité ou une quantité de temps en termes de secondes et nanosecondes. On peut y accéder en utilisant d'autres unités basées sur la durée, telles que sous forme de minutes et d’heures. De plus, l’unité DAYS peut être utilisée et est traitée comme étant exactement égale à 24 heures, en 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 soulève une UnsupportedTemporalTypeException:

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

Alors, quelle est la méthode recommandée pour extraire des minutes et des heures d’un objet de durée? Devons-nous calculer nous-mêmes à partir du nombre de secondes? Pourquoi a-t-il été mis en œuvre de cette façon?

46
Pierre Henry

"Pourquoi a-t-il été mis en place de cette façon?"

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

Les méthodes TemporalAmount interface et get(TemporalUnit) ont été ajoutées assez tard dans le processus. Personnellement, je n’étais pas entièrement convaincue que nous avions suffisamment de preuves de la bonne façon de travailler la conception dans ce domaine, mais j’étais légèrement tordue au bras pour ajouter TemporalAmount. Je crois que, ce faisant, nous avons légèrement confondu l’API.

Avec le recul, je crois que TemporalAmount contient les bonnes méthodes, mais j'estime que get(TemporalUnit) aurait dû 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 tels que l'appel de get(ChronoUnit.MINUTES) à Duration.

Donc, la façon de penser à get(TemporalUnit) est d’imaginer un cadre de bas niveau affichant le montant sous la forme Map<TemporalUnit, Long>Duration est un Map de taille deux avec les clés SECONDS et NANOS.

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

Globalement, le meilleur conseil pour le code d'application est d'ignorer la méthode get(TemporalUnit). Utilisez plutôt getSeconds(), getNano(), toHours() et toMinutes().

Enfin, une façon d'obtenir "hh: mm: ss" d'un Duration consiste à faire:

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

Pas beau du tout, mais ça marche moins d'une journée.

Nouvelles méthodes to…Part en Java 9

JDK-8142936 issue est maintenant implémenté dans Java 9, en ajoutant les méthodes suivantes pour accéder à chaque partie d'un Duration.

  • toDaysPart
  • toHoursPart
  • toMinutesPart
  • toSecondsPart
  • toMillisPart
  • toNanosPart
58
JodaStephen

La documentation dit:

Cela renvoie une valeur pour chacune des deux unités prises en charge, SECONDS et NANOS. Toutes les autres unités lèvent une exception.

Donc, la meilleure réponse: c'est la façon dont ils l'ont conçue.

Vous pouvez utiliser d'autres méthodes pour l'obtenir dans hours :

long hours = duration.toHours();

ou minutes :

long minutes = duration.toMinutes();
27
blgt

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#toString:

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);
7
assylias

Je voudrais ajouter à la réponse de bigt (+1) qui a souligné l'utile toHours, toMinutes et d'autres méthodes de conversion. La spécification de la durée indique:

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

La plage d'une durée nécessite le stockage d'un nombre plus grand que long. Pour y parvenir, la classe stocke un long représentant les secondes et un int représentant une nanoseconde de seconde, qui sera toujours compris entre 0 et 999 999 999.

Il existe diverses méthodes getter 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é à secondes et nanos. Ces méthodes getter extraient les données directement à partir de l'instance de durée et sont sans perte. 

En revanche, il existe diverses méthodes to, y compris toDays, toHours, toMillistoMinutes et toNanos qui font conversion sur la valeur de durée. Ces conversions entraînent des pertes, car elles impliquent la troncature des données. Elles peuvent également générer 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 effectuent des conversions.

7
Stuart Marks

Supprimer Hourse puis obtenir des minutes

long hours = attendanceDuration.toHours(); long minutes = attendanceDuration.minusHours(hours).toMinutes();

0
user9078671