Skip to content

Commit a95bb7a

Browse files
committed
test(bigquery-jdbc): reference ITs for timestamp time zone handling
1 parent a977ef5 commit a95bb7a

5 files changed

Lines changed: 801 additions & 48 deletions

File tree

‎java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITBigQueryJDBCTest.java‎

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.google.cloud.bigquery.jdbc.it;
1818

1919
import static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.jupiter.api.Assertions.assertAll;
2021
import static org.junit.jupiter.api.Assertions.assertEquals;
2122
import static org.junit.jupiter.api.Assertions.assertFalse;
2223
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -57,6 +58,7 @@
5758
import java.time.Instant;
5859
import java.time.LocalTime;
5960
import java.time.ZoneId;
61+
import java.time.ZoneOffset;
6062
import java.time.format.DateTimeFormatter;
6163
import java.util.Calendar;
6264
import java.util.Properties;
@@ -1655,12 +1657,16 @@ public void testPreparedStatementDateTimeValues() throws SQLException {
16551657

16561658
bigQueryStatement.execute(String.format(createTableQuery, DATASET, TABLE_NAME1));
16571659

1660+
Instant moment = Instant.parse("2025-12-03T12:34:56.123Z");
1661+
Time noon = Time.valueOf(LocalTime.NOON);
1662+
Date date = Date.valueOf("2025-12-03");
1663+
16581664
PreparedStatement insertPs = bigQueryConnection.prepareStatement(insertQuery);
16591665
insertPs.setString(1, "dishwasher");
16601666
insertPs.setInt(2, 1);
1661-
insertPs.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
1662-
insertPs.setTime(4, Time.valueOf(LocalTime.NOON));
1663-
insertPs.setDate(5, Date.valueOf("2025-12-3"));
1667+
insertPs.setTimestamp(3, Timestamp.from(moment));
1668+
insertPs.setTime(4, noon);
1669+
insertPs.setDate(5, date);
16641670

16651671
int insertStatus = insertPs.executeUpdate();
16661672
assertEquals(1, insertStatus);
@@ -1669,22 +1675,65 @@ public void testPreparedStatementDateTimeValues() throws SQLException {
16691675
Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
16701676
insertPs.setString(1, "refrigerator");
16711677
insertPs.setInt(2, 2);
1672-
insertPs.setTimestamp(3, new Timestamp(System.currentTimeMillis()), utcCal);
1673-
insertPs.setTime(4, Time.valueOf(LocalTime.NOON), utcCal);
1674-
insertPs.setDate(5, Date.valueOf("2025-12-03"), utcCal);
1678+
insertPs.setTimestamp(3, Timestamp.from(moment), utcCal);
1679+
insertPs.setTime(4, noon, utcCal);
1680+
insertPs.setDate(5, date, utcCal);
16751681

16761682
int insertStatus2 = insertPs.executeUpdate();
16771683
assertEquals(1, insertStatus2);
16781684

1685+
// Read the stored values server-side so no driver temporal conversion is involved.
16791686
ResultSet rs =
16801687
bigQueryStatement.executeQuery(
1681-
String.format("SELECT COUNT(*) AS row_count\n" + "FROM %s.%s", DATASET, TABLE_NAME1));
1682-
rs.next();
1688+
String.format(
1689+
"SELECT IntegerField, UNIX_MILLIS(TimestampField), CAST(TimeField AS STRING),"
1690+
+ " CAST(DateField AS STRING) FROM %s.%s ORDER BY IntegerField",
1691+
DATASET, TABLE_NAME1));
1692+
1693+
assertTrue(rs.next());
1694+
assertEquals(1, rs.getInt(1));
1695+
long plainTimestamp = rs.getLong(2);
1696+
String plainTime = rs.getString(3);
1697+
String plainDate = rs.getString(4);
1698+
assertTrue(rs.next());
16831699
assertEquals(2, rs.getInt(1));
1700+
long calTimestamp = rs.getLong(2);
1701+
String calTime = rs.getString(3);
1702+
String calDate = rs.getString(4);
1703+
assertFalse(rs.next());
16841704

1705+
// Drop before asserting so a failure does not leak the table.
16851706
String dropQuery = String.format("DROP TABLE %s.%s", DATASET, TABLE_NAME1);
16861707
int dropStatus = bigQueryStatement.executeUpdate(dropQuery);
16871708
assertEquals(0, dropStatus);
1709+
1710+
assertAll(
1711+
// Row 1: plain setters.
1712+
() ->
1713+
assertEquals(
1714+
moment.toEpochMilli(), plainTimestamp, "setTimestamp must store the moment"),
1715+
() -> assertEquals("12:00:00", plainTime, "setTime must send its digits"),
1716+
() -> assertEquals("2025-12-03", plainDate, "setDate must send its digits"),
1717+
// Row 2: Calendar setters. The Calendar cannot change a TIMESTAMP moment; for TIME and DATE
1718+
// it is the zone the value is rendered in.
1719+
() ->
1720+
assertEquals(
1721+
moment.toEpochMilli(), calTimestamp, "setTimestamp(ts, cal) must store the moment"),
1722+
() ->
1723+
assertEquals(
1724+
Instant.ofEpochMilli(noon.getTime())
1725+
.atZone(ZoneOffset.UTC)
1726+
.format(DateTimeFormatter.ofPattern("HH:mm:ss")),
1727+
calTime,
1728+
"setTime(t, cal) must send the time of t in the Calendar's zone"),
1729+
() ->
1730+
assertEquals(
1731+
Instant.ofEpochMilli(date.getTime())
1732+
.atZone(ZoneOffset.UTC)
1733+
.toLocalDate()
1734+
.toString(),
1735+
calDate,
1736+
"setDate(d, cal) must send the date of d in the Calendar's zone"));
16881737
}
16891738

16901739
@Test
@@ -2560,12 +2609,7 @@ public void validateGetString() throws Exception {
25602609
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS");
25612610
String expectedTimestampString =
25622611
timestampFormatter.format(
2563-
Instant.parse("2023-07-28T12:30:00Z").atZone(ZoneId.systemDefault()).toLocalDateTime());
2564-
String expectedArrayTimestamp =
2565-
String.format(
2566-
"[%s, %s]",
2567-
Timestamp.from(Instant.parse("2023-01-01T01:00:00Z")),
2568-
Timestamp.from(Instant.parse("2023-01-01T02:00:00Z")));
2612+
Instant.parse("2023-07-28T12:30:00Z").atZone(ZoneOffset.UTC).toLocalDateTime());
25692613

25702614
final ImmutableMap<String, Object> stringResults =
25712615
new ImmutableMap.Builder<String, Object>()
@@ -2593,7 +2637,7 @@ public void validateGetString() throws Exception {
25932637
.put("arrayNumeric", "[10.5, 20.5]")
25942638
.put("arrayBignumeric", "[100.1, 200.2]")
25952639
.put("arrayBoolean", "[true, false]")
2596-
.put("arrayTimestamp", expectedArrayTimestamp)
2640+
.put("arrayTimestamp", "[2023-01-01 01:00:00.0, 2023-01-01 02:00:00.0]")
25972641
.put("arrayDate", "[2023-01-01, 2023-01-02]")
25982642
.put("arrayTime", "[01:00:00, 02:00:00]")
25992643
.put("arrayDatetime", "[2023-01-01 01:00:00.0, 2023-01-01 02:00:00.0]")

‎java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/it/ITCallableStatementTest.java‎

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@
3939
import java.sql.Time;
4040
import java.sql.Timestamp;
4141
import java.sql.Types;
42+
import java.time.LocalDate;
43+
import java.time.LocalDateTime;
44+
import java.time.ZoneId;
4245
import java.util.Calendar;
4346
import java.util.Properties;
4447
import java.util.Random;
48+
import java.util.TimeZone;
4549
import org.junit.jupiter.api.AfterAll;
4650
import org.junit.jupiter.api.BeforeAll;
4751
import org.junit.jupiter.api.Test;
@@ -61,6 +65,10 @@ public class ITCallableStatementTest extends ITBase {
6165
private static final String CALLABLE_STMT_DML_DELETE_PROC_NAME =
6266
"IT_CALLABLE_STMT_PROC_DML_DELETE_TEST";
6367
private static final String CALLABLE_STMT_DML_TABLE_NAME = "IT_CALLABLE_STMT_PROC_DML_TABLE";
68+
// The Calendar tests pin the JVM zone so the Calendar always differs from it; otherwise the
69+
// driver skips the conversion.
70+
private static final ZoneId CALENDAR_TEST_JVM_ZONE = ZoneId.of("America/New_York");
71+
private static final ZoneId CALENDAR_ZONE = ZoneId.of("Asia/Tokyo");
6472

6573
static Connection bigQueryConnection;
6674
static BigQuery bigQuery;
@@ -316,11 +324,18 @@ public void testSetterGetterDate() throws SQLException {
316324
public void testSetterGetterDateCal() throws SQLException {
317325
CallableStatement callableStatement = this.bigQueryConnection.prepareCall("call testProc('?')");
318326
assertNotNull(callableStatement);
319-
Date expected = new Date(1L);
320-
Calendar cal = Calendar.getInstance();
321-
callableStatement.setDate(CALLABLE_STMT_PARAM_KEY, expected, cal);
322-
Date actual = callableStatement.getDate(CALLABLE_STMT_PARAM_KEY, cal);
323-
assertEquals(expected, actual);
327+
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(CALENDAR_ZONE));
328+
Date expected =
329+
new Date(LocalDate.of(2025, 1, 1).atStartOfDay(CALENDAR_ZONE).toInstant().toEpochMilli());
330+
TimeZone originalJvmZone = TimeZone.getDefault();
331+
TimeZone.setDefault(TimeZone.getTimeZone(CALENDAR_TEST_JVM_ZONE));
332+
try {
333+
callableStatement.setDate(CALLABLE_STMT_PARAM_KEY, expected, cal);
334+
Date actual = callableStatement.getDate(CALLABLE_STMT_PARAM_KEY, cal);
335+
assertEquals(expected, actual);
336+
} finally {
337+
TimeZone.setDefault(originalJvmZone);
338+
}
324339
}
325340

326341
@Test
@@ -427,11 +442,22 @@ public void testSetterGetterTime() throws SQLException {
427442
public void testSetterGetterTimeCal() throws SQLException {
428443
CallableStatement callableStatement = this.bigQueryConnection.prepareCall("call testProc('?')");
429444
assertNotNull(callableStatement);
430-
Time expected = new Time(1L);
431-
Calendar cal = Calendar.getInstance();
432-
callableStatement.setTime(CALLABLE_STMT_PARAM_KEY, expected, cal);
433-
Time actual = callableStatement.getTime(CALLABLE_STMT_PARAM_KEY, cal);
434-
assertEquals(expected, actual);
445+
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(CALENDAR_ZONE));
446+
Time expected =
447+
new Time(
448+
LocalDateTime.of(1970, 1, 1, 12, 34, 56)
449+
.atZone(CALENDAR_ZONE)
450+
.toInstant()
451+
.toEpochMilli());
452+
TimeZone originalJvmZone = TimeZone.getDefault();
453+
TimeZone.setDefault(TimeZone.getTimeZone(CALENDAR_TEST_JVM_ZONE));
454+
try {
455+
callableStatement.setTime(CALLABLE_STMT_PARAM_KEY, expected, cal);
456+
Time actual = callableStatement.getTime(CALLABLE_STMT_PARAM_KEY, cal);
457+
assertEquals(expected, actual);
458+
} finally {
459+
TimeZone.setDefault(originalJvmZone);
460+
}
435461
}
436462

437463
@Test
@@ -448,11 +474,17 @@ public void testSetterGetterTimestamp() throws SQLException {
448474
public void testSetterGetterTimestampCal() throws SQLException {
449475
CallableStatement callableStatement = this.bigQueryConnection.prepareCall("call testProc('?')");
450476
assertNotNull(callableStatement);
477+
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(CALENDAR_ZONE));
451478
Timestamp expected = new Timestamp(1L);
452-
Calendar cal = Calendar.getInstance();
453-
callableStatement.setTimestamp(CALLABLE_STMT_PARAM_KEY, expected, cal);
454-
Timestamp actual = callableStatement.getTimestamp(CALLABLE_STMT_PARAM_KEY, cal);
455-
assertEquals(expected, actual);
479+
TimeZone originalJvmZone = TimeZone.getDefault();
480+
TimeZone.setDefault(TimeZone.getTimeZone(CALENDAR_TEST_JVM_ZONE));
481+
try {
482+
callableStatement.setTimestamp(CALLABLE_STMT_PARAM_KEY, expected, cal);
483+
Timestamp actual = callableStatement.getTimestamp(CALLABLE_STMT_PARAM_KEY, cal);
484+
assertEquals(expected, actual);
485+
} finally {
486+
TimeZone.setDefault(originalJvmZone);
487+
}
456488
}
457489

458490
// Block B Tests

0 commit comments

Comments
 (0)