On Tue, 30 Sep 2025 23:06:39 GMT, Pavel Rappo <[email protected]> wrote:
>> We recently [discussed] the possibility of introducing saturating arithmetic >> for deadline computation. Consider this PR as a starting point. Once we >> agree on the implementation, I'll file a CSR. >> >> I created a method in `Instant` to add `Duration`. One could argue that the >> proper way would be to go all the way and create a method in `Temporal` to >> add `TemporalAmount`. Or maybe even expand the functionality, and create an >> additional method in `Temporal` to subtract `TemporalAmount`. >> >> My current thinking is that if we were to do that, there would be a lot of >> expensive, unused code. Saturating logic seems to be only useful for >> `Instant` and `Duration`. >> >> Even if we decide to extend `Temporal` to add/subtract `TemporalAmount`, it >> could always be done later. From the perspective of `Instant`, >> `plus(TemporalAmount)` will be just an overload of `plus(Duration)`. >> >> [discussed]: >> https://mail.openjdk.org/pipermail/core-libs-dev/2025-September/151098.html > > Pavel Rappo has updated the pull request incrementally with one additional > commit since the last revision: > > Slightly improve corner case In 1fe394b I added a test case to exercise behaviour similar to the one discussed previously for `minus`. The test case ultimately does this: Instant.MAX.plus(Duration.between(Instant.MAX, Instant.MIN)) It looks like the result is `Instant.MIN`, but it isn't. It would be `Instant.MIN` if `plus` didn't overflow intermediately. --- Let me again explain what happens, if only for future reference for myself. `Instant.MAX` is 31556889864403199.999,999,999 seconds. `Duration.between(Instant.MAX, Instant.MIN)` is -63113904031622399.999,999,999 seconds. The sum of those is -31557014167219200 seconds, which is exactly `Instant.MIN`. However, the internal representation of `Duration` and `Instant` are not what one might think. While `seconds` can be of either sign, `nanos` are always non-negative, within this range 0 <= nanos <= 999,999,999. So, negative `Duration` -63113904031622399.999,999,999 is represented as -63113904031622200 seconds plus 1 nanosecond. That is, it's a value that is 1 nanosecond closer to 0 than -63113904031622200 is. When `Instant.plus(Duration)` is invoked, it first creates an `Instant` whose seconds are the sum of the seconds and whose nanoseconds are those of the original `Instant`. Any nanoseconds from `Duration` are then added to that `Instant` to produce yet another `Instant`, which holds the final result. The overflow happens in the first step of `plus`, because 31556889864403199 - 63113904031622200 is -31557014167219201, which is less than the -31556889864403200 seconds of `Instant.MIN`. If `plus` proceeded to the second step, which is nanos adjustment, it would get 999,999,999 + 1, which is equal to a whole positive second. It would then add it to -31557014167219201 and get -31557014167219200, which is `Instant.MIN`. ------------- PR Comment: https://git.openjdk.org/jdk/pull/27549#issuecomment-3355846946
