3

I have a simple Postgres test table of id, timestamp with timezone. The test and output below should be self explanatory, but to summarize, I insert a row that has a timestamp with a -6 offset. It is properly inserted into the database, then loaded out of the database with the same hour, but the wrong offset, specifically Z instead of -6.

I've tried setting my database to UTC, and when I manually select at the command line, it properly shows the time in UTC. Set database to mountain, it shows the expected time with an offset of -6.

Forcing the database to various timezones via a statement executed in jOOQ seems to do nothing.

context.execute( "set timezone TO 'GMT';" ); // this has no effect

Forcing my system time to UTC effectively works around the problem, but is for many reasons unacceptable.

TimeZone.setDefault( TimeZone.getTimeZone( "UTC" ) ); // this is a band aid that works, but is not sustainable

Here's the unit test:

@Test
public void confirmDateRoundTripFromDb() throws SQLException, DatatypeConfigurationException
{
    ZonedDateTime testDate = ZonedDateTime.of( 2019, 05, 30, 12, 54, 32, 203, TimeUtilities.CENTRAL_ZONEID );

    final OffsetDateTime testDateAsOffset = testDate.toOffsetDateTime( );

    try( PGConnection dbConnection = DatabaseUtility.getPostgresConnection( _unitTestConfig.getSection("Postgres").getProperties(), _testDbName ) )
    {
        DSLContext context = DSL.using( dbConnection, SQLDialect.POSTGRES );
        DateTestsRecord dateTestsRecord = context.newRecord( DATE_TESTS );
        dateTestsRecord.setTestTimestamp( testDateAsOffset );
        dateTestsRecord.store();

        int id = dateTestsRecord.getId();

        DateTestsRecord insertedRecord = context.selectFrom( DATE_TESTS ).where( DATE_TESTS.ID.eq( id ) ).fetchAny();
        System.out.println( testDateAsOffset );
        System.out.println( insertedRecord.getTestTimestamp() );
    }
}

And the output:

2019-05-30T12:54:32.000000203-05:00
2019-05-30T11:54:32Z

Interestingly, if I add a date in central, the hour is correctly changed to mountain, but the output after the round trip still just happily reports Z.

I assume this is not expected? Am I doing something wrong? If not, any ideas for a workaround that would apply globally? There are several developers on this, I'm not excited about having to handle the date with some special logic every time we select, seems fragile.

I've been running 3.10, but just upgraded to 3.12 with the same results.

Evan
  • 2,441
  • 23
  • 36
  • I had completely forgotten that the project that is exhibiting this issue is using the impossibl pgjdbc-ng driver, and specifically version 0.7.1. One of our devs was working with triggers at one point, but has since abandoned. Apparently, that was a critical point in this issue. In attempting to create an mvce for this issue, I was unable to reproduce with the standard postgres driver, or the impossibl 0.8.2 driver. The impossibl 0.7.1 driver does not seem to work with flyway. But migrating our project away from impossibl fixes the issue and the above test passes. – Evan Sep 16 '19 at 17:01
  • I've deleted the linked question, there is no need for two of these to be floating around. – Evan Sep 16 '19 at 17:02

2 Answers2

5

This is not a jOOQ issue. PostgreSQL doesn't have a data type that corresponds to ZonedDateTime. Its TIMESTAMPTZ or TIMESTAMP WITH TIME ZONE type is really just a java.time.Instant. Consider the manual: https://www.postgresql.org/docs/current/datatype-datetime.html

For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system's TimeZone parameter, and is converted to UTC using the offset for the timezone zone.

There's nothing jOOQ can do here for you.

Do note that jOOQ defaults to mapping TIMESTAMP WITH TIME ZONE types in all SQL databases to java.time.OffsetDateTime, because that's what the JDBC specification does. It is a reasonable default for a vendor agnostic API like JDBC (and jOOQ). But if you want to have PostgreSQL-native behaviour, I would recommend rewriting all of your TIMESTAMPTZ types to INSTANT (if you're using jOOQ 3.12+).

If, for some reason, you need to maintain this information, you will need to store it in a separate column, or a text column as the formatted value.

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • Thanks for responding Lukas, always appreciate you getting on SO to answer questions around jOOQ. I've added an update in response to this in my question. Too long to add in comments. – Evan Sep 05 '19 at 14:46
  • @Evan: May I suggest you revert your edit and ask a new question? It may be less confusing for future visitors of this question... – Lukas Eder Sep 05 '19 at 15:16
  • Happy to do whatever you think is best, I would mention that the edit is selecting data inserted from the original question, and the Java code snippet is an extension of the unit test code from the original as well. – Evan Sep 05 '19 at 15:26
  • Moved to https://stackoverflow.com/questions/57808703/jooq-seems-to-apply-the-current-system-timezone-when-selecting-postgres-timestam @LukasEder – Evan Sep 05 '19 at 15:47
  • @Evan: Will look into it as soon as it is reopened, thanks. – Lukas Eder Sep 05 '19 at 20:54
  • @Evan: Regarding stack overflow, it is an interesting place that takes time to get used to, with many opinions :) Sorry if this has been a confusing experience. In my opinion, new users often edit their questions drastically to give it a new meaning (for a future reader), just like in a forum where we have Q&A&Q&A&... Here, it works differently. The ideal Q&A are very concise and to the point. Editing a question should never alter / extend the original question IMO. Other opinions may differ, of course. – Lukas Eder Sep 05 '19 at 20:56
1

There is an incompatibility between the impossibl pgjdbc driver version 0.7.1 and jOOQ causing offsets not to be applied when selecting timestamp with timezone back out of a postgres database.

In the unlikely event that someone else is also running this combination of jars, recommend updating to pgjdbc 0.8.2 if the features in the impossibl driver are necessary or abandoning if not.

Evan
  • 2,441
  • 23
  • 36
  • Lukas, considering this library now has a newer version, and the version in question doesn't work with the mvce example, I'm not going to be pushing an mvce for this. The mvce project idea is a great one, I wouldn't have realized the library difference existed if I had not started trying to reproduce from scratch. Thanks for the help. – Evan Sep 16 '19 at 17:09