Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid Instant.toEpochMilli() Arithmetic Overflow

Calling the JDKs Instant.toEpochMilli() could result in an arithmetic overflow/underflow (e.g. Instant.MAX.toEpochMilli() or Instant.MIN.toEpochMilli()). I am looking for a simple way to avoid the arithmetic overflow and simply use Long.MAX_VALUE. Here's my current code.

long seconds, millis;

seconds = deadline.getEpochSecond();

if (seconds > Long.MAX_VALUE / 1000 - 1)
   millis = Long.MAX_VALUE;
else if (seconds < Long.MIN_VALUE / 1000 + 1)
   millis = Long.MIN_VALUE;
else
   millis = deadline.toEpochMilli();

It seems like there has to be a cleaner/clearer way to implement this. How would you implement this logic?

I have to be concerned about overflow/underflow because Instant.MAX and Instant.MIN are passed to the method where this code resides.

like image 415
Nathan Avatar asked Mar 10 '23 08:03

Nathan


2 Answers

You can use java.lang.Math.addExact. It will throw an ArithmeticException if overflow occurs. It was added in Java 8.

EDIT

Ok, thinking about this question some more, I think I have a nice solution :

private Instant capped(Instant instant) {
    Instant[] instants = {Instant.ofEpochMilli(Long.MIN_VALUE), instant, Instant.ofEpochMilli(Long.MAX_VALUE)};
    Arrays.sort(instants);
    return instants[1];
}

This method will return an Instant that will never overflow on toEpochMilli().

Simplifying your logic to :

millis = capped(deadline).toEpochMilli();
like image 110
bowmore Avatar answered Mar 20 '23 01:03

bowmore


toEpochMilli throws an exception in case of overflow, so you could just catch that exception:

try {
  millis = deadline.toEpochMillis();
} catch (AritmeticException ignore) {
  millis = deadline.getEpochSecond() < 0 ? Long.MIN_VALUE : Long.MAX_VALUE;
}

This code is simpler and safer than what is written in the question. It is safer because it doesn't try to re-implement the boundary logic inside toEpochMillis().

There might be a performance issue with throwing and catching exceptions. It depends on how often an exception is thrown. If an exception is thrown most of the time, then this will perform worse unless the JVM can optimize this away. If an exception is rarely thrown, then the performance will be fine.

The JVM might be able to optimize this away but maybe not.

like image 35
assylias Avatar answered Mar 20 '23 01:03

assylias