Почему я не могу получить продолжительность в минутах или часах в java.time?
Из Duration
класс в новом JSR 310 date API (пакет java.time), доступный в Java 8 и более поздних версиях, javadoc говорит:
Этот класс моделирует количество или количество времени в секундах и наносекунд. Доступ к нему можно использовать с использованием других единиц, основанных на длительности, таких как как минуты и часы. Кроме того, можно использовать блок DAYS и обрабатывается как ровно 24 часа, таким образом игнорируя эффекты летнего времени.
Итак, почему следующий код сбой?
Duration duration = Duration.ofSeconds(3000);
System.out.println(duration.get(ChronoUnit.MINUTES));
Возникает UnsupportedTemporalTypeException
:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Minutes
at java.time.Duration.get(Duration.java:537)
Итак, каков рекомендуемый способ извлечения минут и часов из объекта продолжительности? Нужно ли нам вычислять себя от количества секунд? Почему это было реализовано именно так?
Ответы
Ответ 1
"Почему это было реализовано именно так?"
Другие ответы касаются методов toXxx()
, которые позволяют запрашивать часы/минуты. Я попытаюсь разобраться с тем, почему.
Интерфейс TemporalAmount
и get(TemporalUnit)
был добавлен довольно поздно в этом процессе. Я лично не был полностью убежден, что у нас было достаточно доказательств правильного способа работы над проектом в этой области, но он слегка перекручен, чтобы добавить TemporalAmount
. Я считаю, что при этом мы немного путаем API.
В ретроспективе я считаю, что TemporalAmount
содержит правильные методы, но я считаю, что get(TemporalUnit)
должно было иметь другое имя метода. Причина в том, что get(TemporalUnit)
- это, по сути, метод на уровне структуры - он не предназначен для повседневного использования. К сожалению, имя метода get
не подразумевает этого, что приводит к ошибкам, например, при вызове get(ChronoUnit.MINUTES)
на Duration
.
Итак, способ думать о get(TemporalUnit)
состоит в том, чтобы представить низкоуровневую структуру, просматривающую сумму как Map<TemporalUnit, Long>
, где Duration
является Map
размера два с ключами SECONDS
и NANOS
.
Таким же образом, Period
рассматривается из низкоуровневых фреймворков как Map
размера три - DAYS
, MONTHS
и YEARS
(к счастью, имеет меньше шансов на ошибки).
В целом, лучший совет для кода приложения - игнорировать метод get(TemporalUnit)
. Вместо этого используйте getSeconds()
, getNano()
, toHours()
и toMinutes()
.
Наконец, один способ получить "hh: mm: ss" из Duration
:
LocalTime.MIDNIGHT.plus(duration).format(DateTimeFormatter.ofPattern("HH:mm:ss"))
Совсем не очень, но он работает на длительность менее одного дня.
Новые методы to…Part
в Java 9
JDK-8142936 теперь реализована в Java 9, добавив следующие методы для доступа к каждой части Duration
.
-
toDaysPart
-
toHoursPart
-
toMinutesPart
-
toSecondsPart
-
toMillisPart
-
toNanosPart
Ответ 2
В документации говорится:
Это возвращает значение для каждого из двух поддерживаемых единиц, SECONDS и NANOS. Исключение составляют все остальные блоки.
Итак, лучше всего догадайся, что так оно и было.
Вы можете использовать некоторые другие методы, чтобы получить его в hours:
long hours = duration.toHours();
или minutes:
long minutes = duration.toMinutes();
Ответ 3
Я хотел бы добавить к ответу bigt (+1), в котором указывались полезные toHours
, toMinutes
и другие методы преобразования. Спецификация продолжительности говорит:
Этот класс моделирует количество или количество времени в секундах и наносекундах. [...]
Диапазон продолжительности требует хранения числа, большего, чем длинное. Для этого класс хранит длинные представляющие секунды и int, представляющие наносекундную секунду, которая всегда будет между 0 и 999999999.
Существует множество методов getter, таких как getSeconds
, getNano
и get(TemporalUnit)
. Учитывая, что продолжительность представлена в виде пары (секунд, нано), ясно, почему get(TemporalUnit)
ограничено секундами и нано. Эти методы getter извлекают данные непосредственно из экземпляра продолжительности и без потерь.
В отличие от этого существует множество методов, включая toDays
, toHours
, toMillis
toMinutes
и toNanos
, которые преобразуют в значение продолжительности. Эти преобразования являются потерями в том, что они связаны с усечением данных, или они могут генерировать исключение, если значение продолжительности не может быть представлено в запрошенном формате.
Это явно часть дизайна, что get-методы извлекают данные без преобразования, а to-methods выполняют какие-то преобразования.
Ответ 4
Чтобы получить компоненты "час/минута/секунда" с "нормализованным" способом, вам нужно их вычислить вручную - код, приведенный ниже, по существу копируется из метода 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);