Adam Kotwasinski
Adam Kotwasinski

Reputation: 4564

How to convert from long+TimeUnit to Duration?

I'm migrating some signatures from f(long dur, TimeUnit timeUnit) to f(Duration duration), and would like to implement the former with the latter.

Being on Java 8, I can't find any API to easily convert the long+TU to a Duration, the only idea that comes to me is to do something ugly like:

static Duration convert(long dur, TimeUnit timeUnit) {
  switch (timeUnit) {
    case DAYS:
      return Duration.ofDays(dur);
    case HOURS:
      /* alternative, but (again) I don't have an easy conversion from TimeUnit -> ChronoUnit */
      return Duration.of(dur, ChronoUnit.HOURS);
    case ..... /* and so on */
  }
}

Or did I miss some API?

Upvotes: 8

Views: 5641

Answers (3)

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 29058

Java 9+

You can use static method Duration.of(long, TemporalUnit).

It expects an amount as long, and a TemporalUnit, so you need to convert the TimeUnit into ChronoUnit.

static Duration convert(long dur, TimeUnit timeUnit) {
    return Duration.of(dur, timeUnit.toChronoUnit());
}

Method toChronoUnit() was introduced in JDK version 9.

Java 8

With Java 8 you can translate TimeUnit into ChronoUnit using ThreeTen library's utility method Temporals.chronoUnit​(TimeUnit).

If you don't want to introduce a dependency on this library in your project, you can make use of the utility method provided in the answer by Paul.

Upvotes: 12

Paul
Paul

Reputation: 20091

You're on the right track. Since you think the right track is ugly the solution is to hide the ugliness! Here's the implementation of TimeUnit.toChronoUnit() from OpenJDK:

/**
 * Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}.
 *
 * @return the converted equivalent ChronoUnit
 * @since 9
 */
public ChronoUnit toChronoUnit() {
    switch (this) {
    case NANOSECONDS:  return ChronoUnit.NANOS;
    case MICROSECONDS: return ChronoUnit.MICROS;
    case MILLISECONDS: return ChronoUnit.MILLIS;
    case SECONDS:      return ChronoUnit.SECONDS;
    case MINUTES:      return ChronoUnit.MINUTES;
    case HOURS:        return ChronoUnit.HOURS;
    case DAYS:         return ChronoUnit.DAYS;
    default: throw new AssertionError();
    }
}

To keep your code cleaner I would implement a static utility method based on above (i.e. pass in a TimeUnit parameter) and get the ChronoUnit without doing a conversion in each case. You'll end up with 1 call to Duration.of(long amount, TemporalUnit unit) and your code will be as beautiful as if you were using Java 9+!

Upvotes: 2

Adam Kotwasinski
Adam Kotwasinski

Reputation: 4564

For Java 8 there is a roundabout solution :\ (we unnecessarily convert from our TU -> millis (or whatever unit) -> Duration) like this:

long dur = ...
TimeUnit unit = ...
Duration result = Duration.ofMillis(unit.toMillis(dur));

Caveat emptor with extremely large values though, Long.MAX_VALUE days cannot be correctly converted into long millis (compared to Duration's ctor that does throw when trying to init with such a value):

final long millis = TimeUnit.DAYS.toMillis(Long.MAX_VALUE); // ouch
final Duration dur = Duration.ofMillis(dur);
System.err.println(dur.toDays() == Long.MAX_VALUE); // returns 'false'

Upvotes: 5

Related Questions