kourouma_coder
kourouma_coder

Reputation: 1098

Duration Class in Java 8 Date/Time API

I need some explination why this code does not compile:

Duration duration = Duration.from(ChronoUnit.DAYS);

Error :

The method from(TemporalAmount) in the type Duration is not applicable for the arguments (ChronoUnit)

As the the documentation here says :

public static Duration from(TemporalAmount amount) Obtains an instance of Duration from a temporal amount. This obtains a duration based on the specified amount. A TemporalAmount represents an amount of time, which may be date-based or time-based, which this factory extracts to a duration.

The conversion loops around the set of units from the amount and uses the duration of the unit to calculate the total Duration. Only a subset of units are accepted by this method. The unit must either have an exact duration or be ChronoUnit.DAYS which is treated as 24 hours. If any other units are found then an exception is thrown.

Parameters: amount - the temporal amount to convert, not null Returns: the equivalent duration, not null Throws: DateTimeException - if unable to convert to a Duration ArithmeticException - if numeric overflow occurs

I know that there are other ways of creating duration instance but I need some explination why this one does not work.

EDIT

When I change like this (Because Period implements TemporalAmount Interface) :

Duration d1 = Duration.from(Period.ofDays(1));

It thows this exception :

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unit must not have an estimated duration

Thanks in advance.

Upvotes: 2

Views: 1844

Answers (3)

MaxZoom
MaxZoom

Reputation: 7753

I believe the confusion here is that the Period object (which implements TemporalAmount interface) can not be used in place of the Duration object (which also implements TemporalAmount interface).
In code:

// Below does not work
Duration d1 = Duration.from(Period.ofDays(1));

// This works fine
Duration d1 = Duration.from(Duration.ofHours(24));

This is because Duration.from method would only accept a subset of ChronoUnit values, that can be accurately converted to hours:

Only a subset of units are accepted by this method. The unit must either have an exact duration or be ChronoUnit.DAYS which is treated as 24 hours

From the Period definition, its value for 1-day (P1D) could be 23 or 24 hours depending on the daylight savings gap. Thus Period has no fixed unit value for which 1-day is always 24 hours, and therefore the UnsupportedTemporalTypeException is thrown.

From the TemporalAmount interface documentation:

Period is a date-based implementation, storing years, months and days. Duration is a time-based implementation, storing seconds and nanoseconds, but providing some access using other duration based units such as minutes, hours and fixed 24-hour days.

Upvotes: 1

Nexevis
Nexevis

Reputation: 4667

I believe @GhostCat's answer sufficiently explains how to correctly use Duration.from and why ChronoUnit.DAYs does not work. However, I want to clarify the source of your confusion and why you think it should work.

This sentence:

The unit must either have an exact duration or be ChronoUnit.DAYS which is treated as 24 hours.

Is mentioning ChronoUnit.DAYS because ChronoUnit.DAYS is an estimation set to 24 hours, and it is not an exact duration like the others. It does not mean you can simply just pass ChronoUnit.DAYS and it will act like the TemporalAmount of 24 hours.

Source from the docs that explains ChronoUnit.DAYS is an estimation.

Sentence reworded to be less confusing:

The unit must have an exact duration except for ChronoUnit.DAYS which is estimated to be 24 hours.

Upvotes: 2

GhostCat
GhostCat

Reputation: 140457

Your question already mentions that this method expects a TemporalAmount. The javadoc for that interface tells us:

Framework-level interface defining an amount of time, such as "6 hours", "8 days" or "2 years and 3 months".

ChronoUnit.DAYS isn't a temporal amount. It is simply a temporal unit of measure. But not an amount: ChronoUnit implements TemporalUnit, not TemporalAmount!

In other words: "Hours" isn't an amount. "6 hours is"!

In other words: you can create a Duration from a unit of measurement. You need to provide something that represents a specific amount of time.

Example:

Duration d = Duration.from(Duration.ofSeconds(5));

should work (as Duration implements TemporalAmount). In that example, you first define a TemporalAmount of 5 seconds, and then you can build "from" that.

Upvotes: 4

Related Questions