javaduration

Duration - Why do extra work when seconds is negative?


This is the method toNanos in class Duration

public long toNanos() {
    long tempSeconds = seconds;
    long tempNanos = nanos;
    // TODO: Here makes me confused
    if (tempSeconds < 0) {
        // change the seconds and nano value to
        // handle Long.MIN_VALUE case
        tempSeconds = tempSeconds + 1;
        tempNanos = tempNanos - NANOS_PER_SECOND;
    }
    long totalNanos = Math.multiplyExact(tempSeconds, NANOS_PER_SECOND);
    totalNanos = Math.addExact(totalNanos, tempNanos);
    return totalNanos;
}

I couldn't understand why need to do extra work when seconds is negative.

Positive numbers' max is 2^63-1 and negative numbers' min is 2^63, looks like it transfer -2^63s,-1ns to -2^63+1s,1000_000_000-1ns, but it has to particate in calculate eventually. In my view this is meaningless because Math.multiplyExact and Math.addExact will throw an Exception when numbers overflow, it doesn't change not matter the judgement existed or not


Solution

  • The extra work is needed for the case Duration.ofNanos(Long.MIN_VALUE) (and some more cases which result in the same number of seconds).

    Duration.ofNanos(Long.MIN_VALUE) is stored as seconds=-9223372037 and nanos=145224192.

    The simple calculation seconds*1_000_000_000 would underflow the range of long values (and therefore the naive Math.multiplyExact(seconds, NANOS_PER_SECOND) would throw an exception). But Duration.ofNanos(Long.MIN_VALUE).toNanos() should not throw an exception, it should return Long.MIN_VALUE.

    They could have written the condition as if (tempSeconds <= -9223372037) { ... } and it would give the same results (i.e. throw for the same values of seconds and nanos) but such a constant is harder to maintain.