New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: use direct wire format -> LocalDate conversion without resorting to java.util.Date, java.util.Calendar, and default timezones #2464
Conversation
I wonder if we should address /all/ of the date and time data types (not just LocalDate), as the discussion (and proposed change) seems pretty similar to where discussion on #1391 is going.
This is the difference between the java/unix epoch of Jan 1, 1970 and the postgres epoch of Jan 1, 2000. Another way to do this (which might be less cryptic) is to define a PG_EPOCH constant and do plus/minus operations from there.
|
I wonder if going with |
At least not for this fix. The previous code with converting between all those old date/time conversions including reflection with setAccessible() to get current timezone are not allowed in Java 9+. So the code above should really be faster! And this old-style calendar magic for guessing zones is also not the fastest. The current code does fixed here did previously:
All not good and errors and bugs waiting everywhere! |
Based on a cursory glance at the implementation, I would suspect it is actually faster. |
That is no question. If user asks for However, what @bokken mentioned was "should we always build the value as |
I have not tested all stuff yet, so this issue is still WIP. Thanks for the comments, will update later. I forgot to mark as Draft. |
I think we can't use java.time Apis for the legacy stuff, because we need to support custom calendars passed in to get date and others. Unless we can integrate that, we have to stay with the legacy code. But we should make sure that if java.time is requested, we should directly deserialize to that. For speed and to keep time zones put of the game. |
250d673
to
69d30c6
Compare
I changed the integer overflow and added infinity handling. The infinity tests also pass. @bokken: I also added the "strange constants" precalculated using |
I looked into the other remianing legacy conversion (
Both are not tested! I set a breakpoint in both if clauses and it was never hit! The 2nd one looks obsolete, because the standard string Timestamp parser can also parse a The first one requires a binary parser from I know, use of I could do those changes in this PR, but as alternative I would start working on it as a new PR, if this one is merged. What do others think? @bokken @vlsi Last sentence for @bokken: At a later stage we may not fully switch to java.time totally (see my comment above), but at least the parsing of string timestamps coming from database should possibly be implemented using java.time and the value-based helper classes |
I would prefer another PR.
|
I seem to recall that the jdbc spec listed specific java.time classes to support (and it is not all of them). I do not see the ability to leverage user provided timezones to be problematic or necessarily even negative. timestamp -> LocalDateTime, which can then default TimeZone or user supplied calendar timezone applied[1] to get to a ZonedDateTime, which can be converted to an Instant[2], which can trivially be used to create a java.sql.TimeStamp. timestamptz is the kind of tricky one. This maps directly to an Instant and/or java.sql.TimeStamp. Getting from a ZonedDateTime to the other data types is pretty straightforward. The time types take a fair amount of massaging, but mapping to the java.time data types is far more straightforward than the java.sql types. I think my proposal is that we pick a preferred internal "native" representation (a java.time type) for each of the pg types and then map how to do the conversions. [1] - https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#atZone-java.time.ZoneId- |
OK, this is a good approach. At least it makes it easy to correctly impement the mapping from wire byte arrays. It also does not need the julian/gregorian conversions, because the java.time API does it correctly (as shown by the LocalDateTime and LocalDate conversions). I think we still need some massaging for the legacy types, where we may need to apply local timezone for the "Local", non-timezoned types. This is how they were originally defined and what also mekes them so horrible to use. But the timezone for this conversion can be picked from the passed Calendar instance to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me modulo small style issues. Thanks for the PR.
pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310Test.java
Outdated
Show resolved
Hide resolved
pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310Test.java
Outdated
Show resolved
Hide resolved
pgjdbc/src/test/java/org/postgresql/test/jdbc42/GetObject310Test.java
Outdated
Show resolved
Hide resolved
Will commit the changes shortly unless someone does that earlier |
Thanks for review. I applied your suggestions. |
…g to java.util.Date, java.util.Calendar, and default timezones Both text and binary formats for date and timestamp contain all the information that is needed to instantialte LocalDate. There's no need to roundtrip with Date and timezones. Converting database results into LocalDate directly reduces the number of moving parts and it makes the code easier to follow. fixes pgjdbc#2221
Thanks for merging. I will proceed with a separate PR about |
Just in case, I see you follow the code style that was there in the classes before (I really appreciate that!), however, please, don't hesitate to use Java 8+ features like Historically the driver was Java 6+, so the code idioms are still from the old days. I think the newly added code could just use 8+, especially for the cases like |
The background here was: I copypasted the |
* Release notes for 42.3.4 * small fix to version diff * fix up more than a few release note formats * added recent changes moved release date up to Apr 15/2022
This fixes #2221:
I added a new method to TimestampUtils that directly converts the epoch days to a LocalDate. Interestingly this allows to not use the cryptic proleptic seconds hack. You can pass the plain epoch days from postgres, just added a few number of days -- actually the strange constant at beginning to
toJavaSecs()
method:divided by 86400 (to get it in days). The following code in toJavaSecs is not needed and returns broken results, because
LocalDate
also does its own Julian/Gregorian transformation.I also beefed the test for LocalDate to cycle through all timezones (should not be needed, as timezone is not involved). I also added dates like 0001-01-01 to tests for LocalDate and LocalDateTime.