FIX - Issue 325 - Column[Instant] loose nano seconds precision#326
Merged
cchantep merged 1 commit intoJan 6, 2021
Conversation
cchantep
reviewed
Jan 6, 2021
cchantep
reviewed
Jan 6, 2021
cchantep
reviewed
Jan 6, 2021
| withQueryResult( | ||
| timestampList :+ Timestamp.from(instantWithNanoPrecision)) { implicit con => | ||
| SQL("SELECT ts").as(scalar[Instant].single). | ||
| aka("parsed instant") must_=== instantWithNanoPrecision |
Member
There was a problem hiding this comment.
For history, this test without code change:
[error] x be parsed from timestamp with nano precision
[error] parsed instant '2021-01-06T08:45:26.441Z != 2021-01-06T08:45:26.441477Z' (JavaTimeSpec.scala:46)
[error] Actual: ...6.441[]Z
[error] Expected: ...6.441[477]Z
FXHibon
commented
Jan 6, 2021
…o precision that was lost at read time
cchantep
approved these changes
Jan 6, 2021
Member
cchantep
left a comment
There was a problem hiding this comment.
Thanks for your contribution
Contributor
Author
|
hello @cchantep |
Member
|
Rather 2.6.10 |
8 tasks
gaeljw
pushed a commit
that referenced
this pull request
May 24, 2026
…714) * 🐛 fix: preserve nanosecond precision in Column[LocalDateTime] (#525) `columnToLocalDateTime` previously delegated through `temporalValueTo`, which extracts time as `Timestamp#getTime` (millisecond epoch) and reconstructs via `Instant.ofEpochMilli`, truncating sub-millisecond precision. Route through `instantValueTo` instead so `Timestamp#toInstant` preserves nanoseconds, mirroring the pattern of #326 (Instant) and #409 (ZonedDateTime). Regression test added to JavaTimeColumnSpec. Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv> * ♻️ refactor: address #714 review (inline helper, drop comments) Per @gaeljw's review: - Inline the instantToLocalDateTime helper as an `Instant` lambda passed directly to instantValueTo, matching columnToZonedDateTime. - Drop the routing rationale comments; the nano-precision test covers the behaviour. The `case localDateTime: LocalDateTime => Right(localDateTime)` short-circuit stays to avoid a ZoneId.systemDefault round-trip on non-UTC JVMs. Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv> --------- Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request Checklist
Fixes
Fixes #325
Purpose
Fix the default instance of Column[Instant] in the JavaTimeColumn trait, so we don't loose the nano second precision during the SQL result reads.
Background Context
When reading an SQL result, TIMESTAMP[TZ] from database is mapped on the java.sql.Timestamp type. Therefore, the Column[Instant] should be able to transform a given java.sql.Timestamp into an java.time.Instant
As java.sql.Timestamp inherits java.util.Date, the first branch of following pattern-matching will be selected
https://github.com/playframework/anorm/blob/master/core/src/main/scala/anorm/Column.scala#L715
The problem is that java.util.Date is precised at the miliseconds level, and not the nano seconds level. Dealing with a java.sql.Timestamp as as java.util.Date will loose this precision, as we can understand immediatly with the following code:
Instant ofEpochMilli date.getTime(getTime returns EPOCH miliseconds, as explained in javadoc)
I wonder why the pattern-matching wasn't using directly the java.sql.Timestamp type? Maybe is there an hidden reason I couldn't understand?
Adding a line (in first position) with a pattern on java.sql.Timestamp seems to be ok, especially since Timestamp can be directly converted to Instant with the method .toInstant.
The 2 lines that matches TimestampWrapper1 and TimestampWrapper2 would loose in the same way, because it build the Instant using only the miliseconds.
I took this opportunty to use ts.toInstant here to, to avoid silent data loss behavior.
Actually, I'm not sure to understand when these TimestampWrapper become useful, but I might not have the full picture I my mind.
References
The issue is explained in details here #325