15

I have a best practices question with regards to mapping Instant to PostgreSQL TIMESTAMP.

We've updated our app to Java 15 and the new enhancement of the system clock to nanosecond precision ( https://bugs.openjdk.java.net/browse/JDK-8242504 ) is incompatible with the TIMESTAMP limitations in Postgres. Time is different depending on the underlying OS, and Instant in Mac (Big Sur) does not give time in nanoseconds but in Linux does.

We use Instant types across our codebase. Our tests are comparing objects of type Instant in memory vs fetched so they fail depending on the OS they're running in.

In Linux, the Instant object in memory has a precision of nanoseconds, whilst the Postgres stored Instant (TIMESTAMP) has a precision of microseconds. The assertions fail:

java.lang.AssertionError: expected [2021-01-04T19:32:23.726475249Z] but found [2021-01-04T19:32:23.726475Z]

In Mac, the Instant object has a precision of microseconds which aligns adequately with the Timestamp precision of Postgres, so the tests pass as they've always done so far.

We would like to avoid truncating Instant or adding plugins to PG to support nanoseconds.

How do others deal with this issue in a robust comprehensive manner?

Alan Cabrera
  • 694
  • 1
  • 8
  • 16
catch22
  • 1,564
  • 1
  • 18
  • 41
  • 7
    As is, the best possible answer is "your tests are flawed, fix 'em" - maybe share some snippets of code to explain what you want to test – Gyro Gearless Jan 06 '21 at 11:31
  • 25
    Truncating `Instant` using `Instant.truncatedTo` *is* the elegant solution. Making assumptions about precision that are not guaranteed by the documentation is the wrong approach. – Erwin Bolwidt Jan 06 '21 at 11:31
  • 1
    @ErwinBolwidt , you might be right but for a grown project this solution is painful and doesn't seem to marry with the "backwards compatibility" motto by Java. – catch22 Jan 07 '21 at 06:00
  • 4
    @catch22 I disagree with you. "backwards compatibility" refers only to things which are guaranteed by the documentation. There was no guaraantee about that before. Any improvement has the risk to break someone's code. – Dorian Gray Jan 09 '21 at 21:45
  • 1
    [Obligatory XKCD](https://xkcd.com/1172/). Otherwise I agree wit @DorianGray - truncating `Instant` appears to be the correct solution. Maybe you can find a good way (with something like [IntelliJ structural search and replace](https://www.jetbrains.com/help/idea/structural-search-and-replace.html) to automatically put the `truncateTo` call into your assertions. – Nicolai Parlog Jan 19 '21 at 19:08
  • 1
    Truncating `Instant` using `Instant.truncatedTo()` is one solution, although not a robust one since it relies on the earnest effort of every engineer. For us, nanoseconds sneak in when using `Instant.now()` or `Clock.instant()`. We have no need for nanoseconds and intend to standardize on using a custom `Clock` that truncates to microseconds and we have a CI quality gate that prohibits the use of `Instant.now()`. – Alan Cabrera Feb 26 '23 at 15:43

0 Answers0