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();
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:
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);