I'm confused about using PostgreSQL's TIMESTAMPTZ type with the official JDBC driver.
Correct me if I'm wrong, but PostgreSQL and Java store TIMESTAMTZ and java.util.Date
identically: as the number of the millis from the Begin of Unix, defined as 1970-01-01 00:00:00 UTC.
Therefore, technically, we are operating on the same Long value, and we should expect no problems.
However, we've got quite a lot of problems with the code doing a lot of transformations in one or other direction, that were replaced by even more complex transformations, which happen to work afterwards. The end result was a bit similar to https://stackoverflow.com/a/6627999/5479362, with transforming to UTC in both directions. Developing under Windows, where changing timezone is blocked, makes things not easier to debug.
If I have a PostgreSQL table with the column:
last_modified TIMESTAMP WITH TIMEZONE
and I want to query it with the Date instance:
Date modifiedAfter = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss").parse("2021-06-11 15:20:00");
PreparedStatement ps = conn.prepareStatement("Select * from mytable where last_modified > ?");
ps.setDate(1, modifiedAfter);
Than it will work correctly, because PostgreSQL JDBC driver will translate the java Date to the UTC Long, using the Locale of my java program, and the the DB server will use its own Locale when that date will be queried?
Or those conversions are not handled correctly if the Locale of the server differs from the Locale of the client, therefore I need to operate only on UTC dates?
The issue that I have with the answer linked above is, that the OP has claimed that it 'works for him', which means, that the Java always reads what was written, but not necessarily, that the value is stored correctly in the DB, so that other clients would read what is expected.
Is the way above the correct way of handling TIMESTAMTZ to assure, that both Java code, and the output of the query in PSQL console would give the consistent result? If not, what's the correct solution?
I expect, that when I write '2021-11-06 15:00:00' with my Java program running with TimeZone +4:
Don't use java.util.Date
, use java.time.OffsetDateTime
OffsetDateTime modifiedAfter = OffsetDateTime.of(2021, 6, 11, 15, 20, 0, 0, ZoneOffset.UTC);
ps.setObject(1, modifiedAfter);
Do the same when reading the value:
ResultSet rs = statement.executeQuery(...);
while (rs.next()) {
OffsetDateTime odt = rs.getObject(1, OffsetDateTime.class);
....
}
If you don't care about time zones at all, and are sure that everything will always be specified with the same time zone (e.g. UTC), then use timezone
as the column data type in Postgres.
Then use LocalDateTime
instead of OffsetDateTime
in Java