Reputation: 90023
Given two java.time.Duration
instances, how does one calculate the whole number of times one Duration fits inside another?
It seems obvious to use first.toNanos() / second.toNanos()
but the Javadoc for this method introduced a tiny snag:
If this duration is too large to fit in a long nanoseconds, then an exception is thrown.
How do we calculate this division without the risk of an overflow?
UPDATE: I am implementing the Token Bucket Algorithm. To that end, I need to know how many "periods" have elapsed since last check in order to populate the bucket with additional tokens. I cannot simply drop nanosecond precision because rates may be specified in terms of nanoseconds.
Upvotes: 3
Views: 3811
Reputation: 798
For Java 9 and later, there's just the method for this on the Duration type.
Upvotes: 1
Reputation: 90023
I figured it out:
/**
* @param first the first duration
* @param second the second duration
* @return {@code first / second}
* @throws IllegalArgument of {@code first}, {@code second} are negative or if {@code second} is zero
*/
public static long divide(Duration first, Duration second)
{
if (first.isNegative())
throw new IllegalArgumentException("first may not be negative");
if (second.isNegative())
throw new IllegalArgumentException("second may not be negative");
if (second.isZero())
throw new IllegalArgumentException("second may not be zero");
BigDecimal firstDecimal = toSeconds(first);
BigDecimal secondDecimal = toSeconds(second);
return firstDecimal.divideToIntegralValue(secondDecimal).longValueExact();
}
/**
* @param duration a duration
* @return the number of seconds in the duration
*/
public static BigDecimal toSeconds(Duration duration)
{
return BigDecimal.valueOf(duration.getSeconds()).add(BigDecimal.valueOf(duration.getNano(), 9));
}
Upvotes: 2
Reputation: 140427
When you turn to the javadoc you will find that the Duration class actually uses seconds and nanoseconds to express itself. And as written there:
The duration uses nanosecond resolution with a maximum value of the seconds that can be held in a long. This is greater than the current estimated age of the universe.
So you should either use only the seconds value. Or if you really need the exact value (including the nanoseconds as well) then use BigInteger. Where you could go so far as to even include the nanoseconds in such a computation.
Upvotes: 9