Paul C
Paul C

Reputation: 8507

Is there a straightforward way to convert java.time.Period into java.time.Duration?

I understand that java.time.Period is an "estimate" and java.time.Duration is exact. Still I'd like to convert a Period into a Duration. Or at least declare a duration of weeks or greater without resorting to tricks.

Even though this compiles, it throws a runtime exception because ChronoUnit.WEEKS and larger return true for ChronoUnit.isDurationEstimated()

var d = Duration.of(2, ChronoUnit.WEEKS);

likewise, this compiles but throws for the same reason:

var d = Duration.from(Period.ofWeeks(2));

Making a round trip from the ISO-8601 string works, but doesn't smell right:

var p = Period.ofWeeks(2);
var d = Duration.parse(p.toString());

Is there a better way to do this?

Upvotes: 5

Views: 3648

Answers (2)

Anonymous
Anonymous

Reputation: 86399

The issue

A java.time.Period is a period of years, months and days. A java.time.Duration is a duration of hours, minutes, seconds and the fraction of a second. They are not compatible, and in general, it does not make sense to convert one to the other.

I am assuming that you still have a practical purpose for trying to do so. Others have already mentioned that you need to decide how long you consider a year and a month since they don’t always have the same length. The same holds true for days: a day hasn’t got the same length always either. Admittedly, it is very often 24 hours, but it may also be 23 or 25 hours or some other length.

As an aside, a further difference is that Period keeps individual fields for years, months and days. You can have a Period of 2 years 28 months and -3 days. A Duration does not keep separate fields and consistently converts 60 seconds into a minute and 60 minutes into an hour.

A Period accepts a count of weeks but converts a week into 7 days. A Duration similarly accepts a count of days and converts a day into 24 hours without regard to the fact I just stated, a day is not always 24 hours.

All of this implies that you may convert a Period of days and/or weeks to a Duration, for example using your string approach, if you accept the assumption that a day is 24 hours. Your method will fail with an exception if the Period has got any years or months in it.

A solution without rounding

java.time includes estimated durations for years and months. These may or may not be appropriate for your purpose. Only you can decide. I can show you how to use them.

public static Duration ofPeriod(Period period) {
    Duration years = ChronoUnit.YEARS.getDuration().multipliedBy(period.getYears());
    Duration months = ChronoUnit.MONTHS.getDuration().multipliedBy(period.getMonths());
    Duration days = ChronoUnit.DAYS.getDuration().multipliedBy(period.getDays());
    return years.plus(months).plus(days);
}

In the 2 weeks example the question gives the same result as in the other answer:

PT336H

Months and years are treated differently. Let’s try a period of 1 year 1 month:

    Period period = Period.of(1, 1, 0);
    Duration duration = ofPeriod(period);
    System.out.println(duration);

PT9496H18M18S

So 9496 hours 18 minutes 18 seconds.

ThreeTen Extra PeriodDuration

The ThreeTen Extra project, developed alongside java.time, includes a PeriodDuration class for a period or duration of years, months, days, hours, mints, seconds and fraction of second. As the name says, a combination of a Period and a Duration. You may see if this could be appropriate for your purpose.

Links:

Upvotes: 9

Oboe
Oboe

Reputation: 2723

There is no direct way to convert from Period to Duration because you have to convert years or months to days, minutes, seconds, millis, or nanos. But, 1 year is equal to 365 or 366 days (leap year)? Or 1 month is equal to 28, 29, 30, or 31 days?

However, you can do an estimate. For example:

public static Duration ofPeriod(Period period) {

    long days = period.getDays() + Math.round((period.toTotalMonths() / 12d) * 365.2425d);

    return Duration.ofDays(days);
}

Then you can do:

Period period = Period.ofWeeks(2);

Duration duration = ofPeriod(period);

System.out.println(duration);

Output:

PT336H

Upvotes: 5

Related Questions