Why can't I get a duration in minutes or hours in java.time?
"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 and get(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 add TemporalAmount
. I believe that in doing so we slightly confused the API.
In hindsight, I believe that TemporalAmount
contains the right methods, but I believe that get(TemporalUnit)
should have had a different method name. The reason is that get(TemporalUnit)
is essentially a framework-level method - it is not designed for day-today use. Unfortunately the method name get
does not imply this, resulting in bugs like calling get(ChronoUnit.MINUTES)
on Duration
.
So, the way to think of get(TemporalUnit)
is to imagine a low-level framework viewing the amount as a Map<TemporalUnit, Long>
where Duration
is a Map
of size two with keys of SECONDS
and NANOS
.
In the same, way, Period
is viewed from the low-level frameworks as a Map
of size three - DAYS
, MONTHS
and YEARS
(which fortunately has less chance of errors).
Overall, the best advice for application code is to ignore the method get(TemporalUnit)
. Use getSeconds()
, getNano()
, toHours()
and toMinutes()
instead.
Finally, one way to get "hh:mm:ss" from a Duration
is to do:
LocalTime.MIDNIGHT.plus(duration).format(DateTimeFormatter.ofPattern("HH:mm:ss"))
Not pretty at all, but it does work for durations less than one day.
New to…Part
methods in Java 9
JDK-8142936 issue now implemented in Java 9, adding the following methods to access each part of a Duration
.
toDaysPart
toHoursPart
toMinutesPart
toSecondsPart
toMillisPart
toNanosPart
The documentation says:
This returns a value for each of the two supported units, SECONDS and NANOS. All other units throw an exception.
So, best guess answer -- that's the way they designed it.
You can use some of the other methods to get it in hours:
long hours = duration.toHours();
or minutes:
long minutes = duration.toMinutes();
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:
This class models a quantity or amount of time in terms of seconds and nanoseconds. [...]
The range of a duration requires the storage of a number larger than a long. To achieve this, the class stores a long representing seconds and an int representing nanosecond-of-second, which will always be between 0 and 999,999,999.
There are a variety of getter methods such as getSeconds
, getNano
, and get(TemporalUnit)
. Given that a duration is represented as a (seconds, nanos) pair, it's clear why get(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
, and toNanos
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.