Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Instant round up to the next second

Tags:

java

java-time

Using the Java Instant class, how can I round up to the nearest second? I don't care if it is 1 millisecond, 15 milliseconds, or 999 milliseconds, all should round up to the next second with 0 milliseconds.

I basically want,

Instant myInstant = ...

myInstant.truncatedTo(ChronoUnit.SECONDS);

but in the opposite direction.

like image 922
Ryan Pelletier Avatar asked Jul 30 '19 14:07

Ryan Pelletier


2 Answers

You can cover the corner case by using .getNano to make sure the time is not exactly even on the second and then add the extra second using .plusSeconds() when there is a value to truncate.

    Instant myInstant = Instant.now();
    if (myInstant.getNano() > 0) //Checks for any nanoseconds for the current second (this will almost always be true)
    {
        myInstant = myInstant.truncatedTo(ChronoUnit.SECONDS).plusSeconds(1);
    }
    /* else //Rare case where nanoseconds are exactly 0
    {
        myInstant = myInstant;
    } */

I left in the else statement just to demonstrate no operations need to be done if it is exactly 0 nanoseconds, because there is no reason to truncate nothing.

EDIT: If you want to check if the time is at least 1 millisecond over a second in order to round up, instead of 1 nanosecond you can then compare it to 1000000 nanoseconds but leave the else statement in to truncate the nanoseconds:

    Instant myInstant = Instant.now();
    if (myInstant.getNano() > 1000000) //Nano to milliseconds
    {
        myInstant = myInstant.truncatedTo(ChronoUnit.SECONDS).plusSeconds(1);
    }
    else
    {
        myInstant = myInstant.truncatedTo(ChronoUnit.SECONDS); //Must truncate the nanoseconds off since we are comparing to milliseconds now.
    }
like image 183
Nexevis Avatar answered Sep 27 '22 21:09

Nexevis


You can use the lambda functional programming streams approach to make this a one liner.

Add a second and truncate. To cover the corner case of being exactly on a second, check the truncated to the original, and only add a second if they differ:

Instant myRoundedUpInstant = Optional.of(myInstant.truncatedTo(ChronoUnit.SECONDS))
                .filter(myInstant::equals)
                .orElse(myInstant.truncatedTo(ChronoUnit.SECONDS).plusSeconds(1));

See this code run line at IdeOne.com.

Instant.toString(): 2019-07-30T20:06:33.456424Z

myRoundedUpInstant(): 2019-07-30T20:06:34Z

…and…

myInstant.toString(): 2019-07-30T20:05:20Z

myRoundedUpInstant(): 2019-07-30T20:05:20Z

Or alternatively, with a slightly different approach:

Instant myRoundedUpInstant = Optional.of(myInstant)
        .filter(t -> t.getNano() != 0)
        .map(t -> t.truncatedTo(ChronoUnit.SECONDS).plusSeconds(1))
        .orElse(myInstant);

See this code run live at IdeOne.com.

myInstant.toString(): 2019-07-30T20:09:07.415043Z

myRoundedUpInstant(): 2019-07-30T20:09:08Z

…and…

myInstant.toString(): 2019-07-30T19:44:06Z

myRoundedUpInstant(): 2019-07-30T19:44:06Z

Above is of course in Java 8 land. I'll leave it as an exercise to the reader to split that out into the more traditional if/else if Optional isn't your thing :-)

like image 28
Michael Berry Avatar answered Sep 27 '22 21:09

Michael Berry