镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

[jdbc-v2] Incorrect timezone transformation when reading from ClickHouse #2496

Closed

Description

@GFriedrich

Description

I've been using the JDBC driver 0.7.2 for quite a while and now decided to update to 0.9.0.
Unfortunately I found that the update to the new driver broke the reading of timestamps. To be exact: Timestamps are read with an incorrect "time" value as the timezone is incorrectly translated to the clients timezone.
This currently blocks me from using any version beyond 0.7.2 (and without applying any workarounds).

Steps to reproduce

  1. Have a ClickHouse server running with UTC (default timezone settings of the driver are used)
  2. Use a client that runs on a different timezone (e.g. GMT+01:00)
  3. Write a timestamp to ClickHouse (e.g. "2025-07-01T01:00:00+01:00")
  4. Check the timestamp inside the ClickHouse DB (which is correctly set to "2025-07-01T00:00:00Z")
  5. Read the timestamp with the same setup
  6. Find that the timestamp is now different (e.g. for this example "2025-07-01T00:00:00+01:00")

Expected Behaviour

Different timezones should not cause a different timestamp to be returned from the DB.

Code Example

I'm using Spring Data repositories to access my data, so the example for me is pretty minimal, which is essentially:

var writtenEntity = clickHouseRepository.save(entityToWrite)
val readEntity = clickHouseRepository.findById(writtenEntity.id)

The timestamps within those entities are now different and it used to work with 0.7.2
No other changes were made besides updating to the new driver version.

Potential location of the issue

I think the issue is at:

return java.sql.Timestamp.valueOf(LocalDateTime.from((TemporalAccessor) value));

The value contains a ZonedDateTime with value 2025-07-01T00:00:00Z which is correctly read from the DB.
Then this is transformed to a LocalDateTime so you get the timestamp without the timezone, so 2025-07-01T00:00:00.
Now when reading things back to the Timestamp, the implementation will use the default Calendar of the machine, which is here a timezone of +01:00, so you end up with 2025-07-01T00:00:00+01:00, which is wrong.
Of course I could set the default calendar to a UTC one, but this would cause other unwanted side effects for my application.

Beside this I also found that the getTimestamp implementation of the ResultSet to be wrong:

public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException {
checkClosed();
try {
ZonedDateTime zdt = reader.getZonedDateTime(columnLabel);
if (zdt == null) {
wasNull = true;
return null;
}
wasNull = false;
Calendar c = (Calendar) (cal != null ? cal : defaultCalendar).clone();
c.set(zdt.getYear(), zdt.getMonthValue() - 1, zdt.getDayOfMonth(), zdt.getHour(), zdt.getMinute(),
zdt.getSecond());
Timestamp timestamp = new Timestamp(c.getTimeInMillis());
timestamp.setNanos(zdt.getNano());
return timestamp;
} catch (Exception e) {
throw ExceptionUtils.toSqlState(String.format("Method: getTimestamp(\"%s\") encountered an exception.", columnLabel), String.format("SQL: [%s]", parentStatement.getLastStatementSql()), e);
}
}

Here again the zdt contains the value of 2025-07-01T00:00:00Z.
This then gets manually translated to the calendar for +01:00 to c with 2025-07-01T00:00:00+01:00.
The transition to the Timestamp afterwards doesn't change things and is then kept at 2025-07-01T00:00:00+01:00.
For this part here I think this broke with #2107
This is because the previous implementation used to use a UTC calendar and only the translation later on to a Timestamp would have added the default machine timezone, like:
zdt with 2025-07-01T00:00:00Z becomes c with 2025-07-01T00:00:00+00:00 becomes Timestamp with 2025-07-01T01:00:00+01:00.
(Of course I don't know if the introduction of the other calendar made sense in other places, but at least for reading the timestamp here it caused wrong results).

Configuration

Client Configuration

Nothing specific - defaults were used

Environment

  • JDBC version: 0.9.0
  • Language version: Java 21
  • OS: Linux

ClickHouse Server

  • ClickHouse Server version: 25.6
  • ClickHouse Server non-default settings, if any: N/A
  • CREATE TABLE statements for tables involved:
CREATE TABLE IF NOT EXISTS my_db.my_table
(
    id             UUID,
    other_id       Int32,
    payload        String,
    timestamp      DateTime64(3, 'UTC')
    ) ENGINE = ReplacingMergeTree()
ORDER BY other_id;

Activity

  1. changed the title [-]Incorrect timezone transformation when reading from ClickHouse[/-] [+][jdbc-v2] Incorrect timezone transformation when reading from ClickHouse[/+] on Jul 13, 2025
  2. modified the milestone: 0.9.2 on Jul 23, 2025
  3. self-assigned this
    on Jul 24, 2025
  4. added this to the 0.9.3 milestone on Aug 20, 2025
  5. chernser commented on Aug 28, 2025

    @chernser
    Contributor

    Good day, @GFriedrich !
    Thank you for reporting the issue!

    I think you are right. I will look into it.

  6. chernser commented on Aug 28, 2025

    @chernser
    Contributor

    Triage:
    we need to fix handling date-time read from DB and avoid extra conversions.
    Data in DB should be converted to a local date time, currently only timezone is set to local but time/date part is in UTC.

  7. modified the milestones: 0.9.3, 0.9.4 on Oct 1, 2025
  8. modified the milestones: 0.9.5, 0.9.6 on Jan 6, 2026
  9. modified the milestones: 0.9.6, 0.9.7 on Jan 21, 2026
  10. chernser commented on Feb 26, 2026

    @chernser
    Contributor

    @GFriedrich

    Setting default calendar to UTC definitely not an option.
    There is com.clickhouse.jdbc.ResultSetImpl#getTimestamp(int, java.util.Calendar) that will redefine timezone.
    If possible you can use getObject(column, ZonedDateTime.class) to get what is read from DB. And it will be much faster read.
    Should be fixed in the 0.9.7.

    We have created a documentation how driver transforms date/time value https://clickhouse.com/docs/integrations/language-clients/java/jdbc_date_time_guide

    Thanks!

  11. GFriedrich commented on Feb 26, 2026

    @GFriedrich
    Author

    Amazing - that is great to hear @chernser
    Thanks so much for tackling it.
    Will give 0.9.7 a shot then once it is out. 🤝

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions