I have postgresql with TIMESTAMP
field, which have Instant with date and time. For example: 2021-10-13T15:04:24.944921Z
.
As you can see, there are 6 digits after comma - 944921
. But what if I have more digits, for example: 2021-10-13T07:14:47.791616921Z
. How can I correctly round such Instant
to 2021-10-13T07:14:47.791617Z
?
CodePudding user response:
The code is short but requires a bit of explanation. You are right, the best we have is the truncatedTo
method, and it always rounds down. Instead we want the half-up rounding that we learned in school: If the 7th decimal is 4 or less, round down. If it is 5 or higher, round up.
To obtain this I first add 500 nanoseconds. Then truncate. If the 7th decimal was 4 or less, it is still 9 or less, so the digits before it have not been changed, and truncation will do the rounding-down that we want. If the 7th decimal was 5 or more, adding 500 nanoseconds will overflow it, the 6th decimal will be incremented by 1, and the 7th decimal will end up in the 0 through 4 range. Then truncation will effectively do the rounding up of the original value that we wanted.
Instant sourceValue = Instant.parse("2021-10-13T07:14:47.791616921Z");
Instant rounded = sourceValue.plusNanos(500).truncatedTo(ChronoUnit.MICROS);
System.out.println(rounded);
Output is the desired:
2021-10-13T07:14:47.791617Z
Let’s try the edge cases too.
Instant sourceValue = Instant.parse("2021-10-13T07:14:00.000000499Z");
2021-10-13T07:14:00Z
Instant sourceValue = Instant.parse("2021-10-13T07:14:59.999999500Z");
2021-10-13T07:15:00Z