É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
>>>
>>>

Reply via email to