ClickHouse / ClickHouse/clickhouse-java

V2 driver ignores column timezones when reading via getTimestamp

Abierto
#2,787 16 comentarios 2 reacciones 1 asignado Reclamado por @chernser Ver en GitHub
bug question
Lenguaje dominante
Java
Estrellas
1.6k
Forks
636
Merge medio
2 d 23 h
PR fusionados (30 d)
29

Descripción

## Description

### Steps to reproduce

When running the program below (see Code Example) I get the following output

```
Table test1 created.
Original Timestamp: 2026-03-12 22:58:08.000 (millis: 1773356288000)
Record inserted.
Read t_tokyo: 2026-03-13 07:58:08.0 (millis: 1773388688000)
Read t_ny: 2026-03-12 18:58:08.0 (millis: 1773341888000)
```

Note that one Timestamp value is inserted for both columns (as number of millis since epoch so it should be timezone independent) but when read back 2 different values are returned that are not equal to the original one.

I believe the issue is in https://github.com/ClickHouse/clickhouse-java/blob/268f1b7227ae16d144e81f09b4f7f71b2c2e59e4/jdbc-v2/src/main/java/com/clickhouse/jdbc/ResultSetImpl.java#L1086 that completely ignores the column's timezone (`zdt.getTimeZone()`) and uses JVM default timezone to convert `LocalDateTime` value to `java.sql.Timestamp`.

### Expected Behaviour

I expect V2 driver to behave the same way as V1 driver and correctly produce 3 identical timestamps:

```
Table test1 created.
Original Timestamp: 2026-03-12 23:02:25.000 (millis: 1773356545000)
Record inserted.
Read t_tokyo: 2026-03-12 23:02:25.0 (millis: 1773356545000)
Read t_ny: 2026-03-12 23:02:25.0 (millis: 1773356545000)
```

### Code Example

```java

package com.example;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Properties;

public class App {
public static void main(String[] args) {
String url = "jdbc:clickhouse://localhost:8123/default";
Properties props = new Properties();
props.setProperty("user", "default");
props.setProperty("password", "");

try (Connection conn = DriverManager.getConnection(url, props)) {
try (Statement stmt = conn.createStatement()) {
// 1. Create the table
stmt.execute("DROP TABLE IF EXISTS test1");
stmt.execute("CREATE TABLE test1 (" +
" t_tokyo DateTime(3, 'Asia/Tokyo'), " +
" t_ny DateTime(3, 'America/New_York') " +
") ENGINE = MergeTree ORDER BY t_tokyo");
System.out.println("Table test1 created.");
}

// 2. Insert record
Timestamp originalTimestamp = new Timestamp(System.currentTimeMillis());
System.out.println("Original Timestamp: " + originalTimestamp + " (millis: " + originalTimestamp.getTime() + ")");

String insertSql = "INSERT INTO test1 (t_tokyo, t_ny) VALUES (?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(insertSql)) {
pstmt.setTimestamp(1, originalTimestamp);
pstmt.setTimestamp(2, originalTimestamp);
pstmt.executeUpdate();
System.out.println("Record inserted.");
}

// 3. Read back
String selectSql = "SELECT t_tokyo, t_ny FROM test1";
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(selectSql)) {
if (rs.next()) {
Timestamp readTokyo = rs.getTimestamp("t_tokyo");
Timestamp readNy = rs.getTimestamp("t_ny");

System.out.println("Read t_tokyo: " + readTokyo + " (millis: " + readTokyo.getTime() + ")");
System.out.println("Read t_ny: " + readNy + " (millis: " + readNy.getTime() + ")");
} else {
System.out.println("No record found.");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

```

#### Environment
* Client version: 0.9.7
* Language version: 25
* OS: Linux

#### ClickHouse Server
* ClickHouse Server version: 26.2.3.2
* ClickHouse Server non-default settings, if any:

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.