Do you remember how everybody was hyped about the new date and time APIs introduced in Java 8? Yes, I was hyped too, although I was using jodatime wherever I could anyway. Now this was a while back and at the time of this writing, Java 10 is out and the latest (or at least a fairly current) release is

java version "10.0.1" 2018-04-17
Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode)

so we all have even saner APIs to deal with dates and times, right? Wrong.

Vince Vaughn screaming “erroneous”

The unsuspecting Dev

Today I was configuring some timeouts at work, and I thought to myself

Why not be explicit about what values and units are used?

It is 2018 and I don’t want or need to see lines like

long timeoutmillis = (long) 420_000 * COMPANY_INTERNAL_TIME_FACTOR * 1e-3 - 1

so, with the help of my trusty IDE autocompletion, I arrived at something much more pleasing to the eye:

Duration.of(90, ChronoUnit.SECONDS).get(ChronoUnit.MILLIS))

Looks pretty good, no? It’s quite explicit about what values are used and about the units they have. Not so fast. A RuntimeException in the logs.

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Millis

Surely, that must be some kind of silly error on my side. A quick check with the documentation confirmed that it was much, much worse. It says, and I kid you not,

This returns a value for each of the two supported units, SECONDS and NANOS. All other units throw an exception.

This cannot be real. IT CANNOT BE SAYING WHAT IT SAYS. But it does. Here’s a screenshot: ̦

Screnshot From JavaDoc

API Design at it’s finest

So somebody, actually multiple people, looked at the proposal and said,

why, yes, let this API accept only 2 units and throw exceptions otherwise. That, right here, is an API worthy of bringing into our specification.

And that’s why, folks, we cannot have nice APIs, not even now, in 2000-freaking-18. But wait, I have another goodie for you. Maybe you saw it already: Calling this method might throw 2 different exceptions:

Throws: DateTimeException – if the unit is not supported UnsupportedTemporalTypeException – if the unit is not supported

Um, which will it throw? Anyway, Duration is quite able to do the conversion I required.

Duration.of(90, ChronoUnit.SECONDS).toMillis();

So if you wanted to convert dynamically, you are required to write a big switch statement or a freaking if-cascade.