Yes, we have utility classes Instants and Durations, and Instants includes methods Instants.saturatedAdd(Instant, Duration) and Instants.saturatedSubtract(Instant, Duration). Each has a modest number of uses in the codebase, about three orders of magnitude less than the number of classes that reference Instant or Duration.
On Tue, 7 Oct 2025 at 14:18, Pavel Rappo <[email protected]> wrote: > Éamonn, Kurt, > > Is there any saturating arithmetic for instant + duration in your code > base? > > > > On Fri, Sep 5, 2025 at 8:58 PM Éamonn McManus <[email protected]> wrote: > > > > As promised, Kurt and I have examined some of the uses of our > Durations.MAX constant. This is a summary of what we see in a random sample > of 30 out of about 700 usages in Google's (giant) codebase. > > > > First, about half of the usages specifically concern deadlines. Many of > them involve a method that sets an RPC deadline and where it is explicitly > documented that you should use Durations.MAX to mean no deadline (or > equivalently, infinite deadline). > > > > Several other usages concern deadline-adjacent concepts such as > time-to-live or cache expiration delay. > > > > A number of usages specifically compare a Duration against Durations.MAX > to recognize the "infinite duration" value. > > > > One usage uses our internal Sleeper interface to do > sleeper.sleep(Durations.MAX), for an indefinite sleep (until interrupted). > > > > In a couple of places, there is a maximum allowed Duration for some > operation, and a user-supplied Duration value is capped by this maximum. > When no maximum is needed, the cap is Durations.MAX. This is similar to the > "sentinel" use case I mentioned earlier. > > > > One case is using Durations.MAX in a test, to ensure that a function > works correctly for all Duration values including the largest one. It is > testing a Kotlin extension function that allows you to write e.g. 5.minutes: > > > > val n = Durations.MAX.toMinutes() > > > > assertThat(n.minutes).isEqualTo(Duration.ofMinutes(n)) > > > > assertFailsWith<ArithmeticException> { (n + 1).minutes } > > > > > > In summary, I think the most interesting use cases fall into these > categories: > > > > to express an effectively-infinite Duration, possibly accompanied by > special-case logic to optimize the exact value Durations.MAX; > > > > to express the absence of an optional cap on a user-supplied Duration > value; > > > > to test that code works correctly even with extreme Duration values. > > > > > > Of these, the first is potentially fragile because of the overflow > problems we discussed. The other two seem unproblematic, though. > > > > > > > > On Thu, 4 Sept 2025 at 15:02, Éamonn McManus <[email protected]> > wrote: > >> > >> Two typical use cases: > >> > >> // 1. Sentinel > >> Duration min = Duration.MAX; > >> for (var foo : something()) { > >> if (foo.duration().compareTo(min) < 0) { > >> min = foo.duration(); > >> } > >> } > >> > >> // 2. "Forever" > >> void frob(Optional<Duration> optionalTimeout) { > >> Duration timeout = optionalTimeout.orElse(Duration.MAX); > >> Instant start = Instant.now(); > >> boolean done = false; > >> while (!done && startTime.until(Instant.now()).compareTo(timeout) < > 0) {...} > >> } > >> > >> The second case illustrates why this is potentially a bit delicate. You > better not write this: > >> > >> void frob(Optional<Duration> optionalTimeout) { > >> Duration timeout = optionalTimeout.orElse(Duration.MAX); > >> Instant deadline = Instant.now().plus(timeout); // oops > >> boolean done = false; > >> while (!done && Instant.now().isBefore(deadline)) {...} > >> } > >> > >> Like Kevin, I am skeptical about Duration.MIN. If it means the most > negative Duration, that is just Duration.MAX.negated(); and if it means the > smallest positive Duration, that is just Duration.ofNanos(1). > >> > >> On Wed, 3 Sept 2025 at 18:32, Roger Riggs <[email protected]> > wrote: > >>> > >>> Hi, > >>> > >>> I'd be interested in the range of use cases for Duration.MAX or MIN. > >>> > >>> But for deadlines, I think the code should compute the deadline from a > Duration of its choice based on the use. > >>> Maybe there is a use for Duration.REALLY_BIG or _SMALL, but that > ignores information about the particular use that is relevant. Its just > sloppy code that doesn't bother to express how long is long enough to meet > operational parameters. > >>> > >>> YMMV, Roger > >>> > >>> On 9/3/25 8:21 PM, Kurt Alfred Kluever wrote: > >>> > >>> Duration.MIN is a whole 'nother bag of worms, because Durations are > signed (they can be positive or negative...or zero). Internally we also > have Durations.MIN, but it's not public ... and along with it, I left > myself a helpful note about naming: > >>> > >>> /** The minimum supported {@code Duration}, approximately -292 > billion years. */ > >>> // Note: before making this constant public, consider that "MIN" > might not be a great name (not > >>> // everyone knows that Durations can be negative!). > >>> static final Duration MIN = Duration.ofSeconds(Long.MIN_VALUE); > >>> > >>> This reminds me of Double.MIN_VALUE (which is the smallest _positive_ > double value) --- we've seen Double.MIN_VALUE misused so much that we > introduced Doubles.MIN_POSITIVE_VALUE as a more descriptive alias. A large > percent of Double.MIN_VALUE users actually want the smallest possible > negative value, aka -Double.MAX_VALUE. > >>> > >>> If we introduce Duration.MIN, I hope it would not be > Duration.ofNanos(1), but rather Duration.ofSeconds(Long.MIN_VALUE). > >>> > >>> On Wed, Sep 3, 2025 at 7:59 PM ecki <[email protected]> wrote: > >>>> > >>>> If you ask me, I don’t find it very useful, It won’t work for > arithmetrics, even the APIs would have a hard time using it (how do you > express the deadline) and APIs with a timeout parameter do have a good > reason for it, better pick “possible” values for better self healing and > unstuck of systems. In fact I would err on the smaller side in combination > with expecting spurious wakeups. > >>>> > >>>> BTW, when you introduce MIN as well, maybe also think about min > precision, min delta or such. Will it always be 1 nano? > >>>> > >>>> Gruß, > >>>> Bernd > >>>> -- > >>>> https://bernd.eckenfels.net > >>>> ________________________________ > >>>> Von: core-libs-dev <[email protected]> im Auftrag von > Pavel Rappo <[email protected]> > >>>> Gesendet: Donnerstag, September 4, 2025 12:41 AM > >>>> An: Kurt Alfred Kluever <[email protected]> > >>>> Cc: Stephen Colebourne <[email protected]>; core-libs-dev < > [email protected]> > >>>> Betreff: Re: Duration.MAX_VALUE > >>>> > >>>> This is useful; thanks. It would be good to see more of your data. > >>>> > >>>> My use case is also duration which practically means **forever**. I > >>>> pass it to methods that accept timeouts, and expect these methods to > >>>> correctly interpret it. > >>>> > >>>> One example of a practical interpretation is > >>>> java.util.concurrent.TimeUnit.convert(Duration). This method never > >>>> overflows; instead, it caps at Long.MAX_VALUE nanoseconds, which is > >>>> roughly 292 years. > >>>> > >>>> Would I be okay, if the proposed duration didn't reflect **forever** > >>>> but instead reflected **long enough**? I think so. But it still > >>>> somehow feels wrong to make it less than maximum representable value. > >>>> > >>>> Personally, I'm not interested in calendar arithmetic, that is, in > >>>> adding or subtracting durations. Others might be, and that's okay and > >>>> needs to be factored in. For better or worse, java.time made a choice > >>>> to be unforgiving in regard to overflow and is very upfront about it. > >>>> It's not only proposed Duration.MAX. The same thing happens if you try > >>>> this > >>>> > >>>> Instant.MAX.toEpochMilli() > >>>> > >>>> I guess my point is that doing calendar arithmetic on an unknown value > >>>> is probably wrong. Doing it on a known huge/edge-case value is surely > >>>> wrong. So back to your data. I would be interested to see what > >>>> triggers overflows for your Durations.MAX. > >>>> > >>>> On Wed, Sep 3, 2025 at 8:45 PM Kurt Alfred Kluever <[email protected]> > wrote: > >>>> > > >>>> > Hi all, > >>>> > > >>>> > Internally at Google, we've had a Durations.MAX constant exposed > for the past 7 years. It now has about 700 usages across our depot, which I > can try to categorize (at a future date). > >>>> > > >>>> > While I haven't performed that analysis yet, I think exposing this > constant was a bit of a mistake. People seem to want to use MAX to mean > "forever" (often in regards to an RPC deadline). This works fine as long as > every single layer that touches the deadline is very careful about > overflow. The only reasonable thing you can do with MAX is compareTo() and > equals(). Attempting to do any simple math operation (e.g., now+deadline) > is going to explode. Additionally, decomposing Duration.MAX explodes for > any sub-second precision (e.g., toMillis()). > >>>> > > >>>> > As we dug into this, another proposal came up which was something > like Durations.VERY_LONG. This duration would be longer than any reasonable > finite duration but not long enough to cause an overflow when added to any > reasonable time. E.g., a million years would probably satisfy both > criteria. This would mean math operations and decompositions won't explode > (well, microseconds and nanoseconds still would), and it could safely be > used as a relative timeout. > >>>> > > >>>> > As I mentioned above, I'd be happy to try to categorize a sample of > our 700 existing usages if folks think that would be useful for this > proposal. > >>>> > > >>>> > Thanks, > >>>> > > >>>> > -Kurt Alfred Kluever (on behalf of Google's Java and Kotlin > Ecosystem team) > >>>> > > >>>> > On Wed, Sep 3, 2025 at 1:53 PM Pavel Rappo <[email protected]> > wrote: > >>>> >> > >>>> >> If I understood you correctly, you think we should also add > >>>> >> Duration.MIN. If so, what use case do you envision for it? Or we > add > >>>> >> if purely for symmetry with Instant? > >>>> >> > >>>> >> On Wed, Sep 3, 2025 at 6:43 PM Pavel Rappo <[email protected]> > wrote: > >>>> >> > > >>>> >> > On Wed, Sep 3, 2025 at 6:06 PM Stephen Colebourne < > [email protected]> wrote: > >>>> >> > > > >>>> >> > > Hmm, yes. Not sure why that didn't get added in Java 8! > >>>> >> > > The constants would be MAX/MIN as per classes like Instant. > >>>> >> > > Stephen > >>>> >> > > >>>> >> > I thought that naming could be tricky :) The public constant > >>>> >> > Duration.ZERO and the public method isZero() are already there. > >>>> >> > However, it does not preclude us from naming a new constant MAX. > >>>> > > >>>> > > >>>> > > >>>> > -- > >>>> > kak > >>>> > >>> > >>> > >>> -- > >>> kak > >>> > >>> >
smime.p7s
Description: S/MIME Cryptographic Signature
