Of the Duration
class in the new JSR 310 date API (java.time package) available in Java 8 and later, the javadoc says :
This class models a quantity or amount of time in terms of seconds and nanoseconds. It can be accessed using other duration-based units, such as minutes and hours.In addition, the DAYS unit can be used and is treated as exactly equal to 24 hours, thus ignoring daylight savings effects.
So, why does the following code crash ?
Duration duration = Duration.ofSeconds(3000);
System.out.println(duration.get(ChronoUnit.MINUTES));
This raises an UnsupportedTemporalTypeException
:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Minutes
at java.time.Duration.get(Duration.java:537)
So what is the recommended way to extract minutes and hours from a duration object ? Do we have to make the calculation ourselves from the number of seconds ? Why was it implemented that way ?
"Why was it implemented that way?"
Other answers deal with the
toXxx()
methods that allow the hours/minutes to be queried. I'll try to deal with the why.The
TemporalAmount
interface andget(TemporalUnit)
method was added fairly late in the process. I personally was not entirely convinced that we had enough evidence of the right way to work the design in that area, but was slightly arm-twisted to addTemporalAmount
. I believe that in doing so we slightly confused the API.In hindsight, I believe that
TemporalAmount
contains the right methods, but I believe thatget(TemporalUnit)
should have had a different method name. The reason is thatget(TemporalUnit)
is essentially a framework-level method - it is not designed for day-today use. Unfortunately the method nameget
does not imply this, resulting in bugs like callingget(ChronoUnit.MINUTES)
onDuration
.So, the way to think of
get(TemporalUnit)
is to imagine a low-level framework viewing the amount as aMap<TemporalUnit, Long>
whereDuration
is aMap
of size two with keys ofSECONDS
andNANOS
.In the same, way,
Period
is viewed from the low-level frameworks as aMap
of size three -DAYS
,MONTHS
andYEARS
(which fortunately has less chance of errors).Overall, the best advice for application code is to ignore the method
get(TemporalUnit)
. UsegetSeconds()
,getNano()
,toHours()
andtoMinutes()
instead.Finally, one way to get "hh:mm:ss" from a
Duration
is to do:Not pretty at all, but it does work for durations less than one day.
New
to…Part
methods in Java 9JDK-8142936 issue now implemented in Java 9, adding the following methods to access each part of a
Duration
.toDaysPart
toHoursPart
toMinutesPart
toSecondsPart
toMillisPart
toNanosPart
To get the hour/minute/second components in a "normalised" way, you need to calculate them manually - the code below is essentially copied from the
Duration#toString
method:By below code i got this duration output:
code example:
Explanation:
By using Duration interface you can easily find the exact String display you want. you just need to reduce the bigger TemporalUnit from current duration.
for example:
The documentation says:
So, best guess answer -- that's the way they designed it.
You can use some of the other methods to get it in hours:
or minutes:
I'd like to add to bigt's answer (+1) that pointed out the useful
toHours
,toMinutes
and other conversion methods. The Duration specification says:There are a variety of getter methods such as
getSeconds
,getNano
, andget(TemporalUnit)
. Given that a duration is represented as a (seconds, nanos) pair, it's clear whyget(TemporalUnit)
is restricted to seconds and nanos. These getter methods extract data directly from the duration instance and are lossless.By contrast, there is a variety of to-methods including
toDays
,toHours
,toMillis
toMinutes
, andtoNanos
that do conversion on the duration value. These conversions are lossy in that they involve truncation of data, or they might throw an exception if the duration value cannot be represented in the requested format.It's clearly part of the design that the get-methods extract data without conversion and the to-methods perform conversions of some sort.