1717package com .google .cloud .bigquery .jdbc .it ;
1818
1919import static com .google .common .truth .Truth .assertThat ;
20+ import static org .junit .jupiter .api .Assertions .assertAll ;
2021import static org .junit .jupiter .api .Assertions .assertEquals ;
2122import static org .junit .jupiter .api .Assertions .assertFalse ;
2223import static org .junit .jupiter .api .Assertions .assertNotNull ;
5758import java .time .Instant ;
5859import java .time .LocalTime ;
5960import java .time .ZoneId ;
61+ import java .time .ZoneOffset ;
6062import java .time .format .DateTimeFormatter ;
6163import java .util .Calendar ;
6264import java .util .Properties ;
@@ -1739,12 +1741,16 @@ public void testPreparedStatementDateTimeValues() throws SQLException {
17391741
17401742 bigQueryStatement .execute (String .format (createTableQuery , DATASET , TABLE_NAME1 ));
17411743
1744+ Instant moment = Instant .parse ("2025-12-03T12:34:56.123Z" );
1745+ Time noon = Time .valueOf (LocalTime .NOON );
1746+ Date date = Date .valueOf ("2025-12-03" );
1747+
17421748 PreparedStatement insertPs = bigQueryConnection .prepareStatement (insertQuery );
17431749 insertPs .setString (1 , "dishwasher" );
17441750 insertPs .setInt (2 , 1 );
1745- insertPs .setTimestamp (3 , new Timestamp ( System . currentTimeMillis () ));
1746- insertPs .setTime (4 , Time . valueOf ( LocalTime . NOON ) );
1747- insertPs .setDate (5 , Date . valueOf ( "2025-12-3" ) );
1751+ insertPs .setTimestamp (3 , Timestamp . from ( moment ));
1752+ insertPs .setTime (4 , noon );
1753+ insertPs .setDate (5 , date );
17481754
17491755 int insertStatus = insertPs .executeUpdate ();
17501756 assertEquals (1 , insertStatus );
@@ -1753,22 +1759,65 @@ public void testPreparedStatementDateTimeValues() throws SQLException {
17531759 Calendar utcCal = Calendar .getInstance (TimeZone .getTimeZone ("UTC" ));
17541760 insertPs .setString (1 , "refrigerator" );
17551761 insertPs .setInt (2 , 2 );
1756- insertPs .setTimestamp (3 , new Timestamp ( System . currentTimeMillis () ), utcCal );
1757- insertPs .setTime (4 , Time . valueOf ( LocalTime . NOON ) , utcCal );
1758- insertPs .setDate (5 , Date . valueOf ( "2025-12-03" ) , utcCal );
1762+ insertPs .setTimestamp (3 , Timestamp . from ( moment ), utcCal );
1763+ insertPs .setTime (4 , noon , utcCal );
1764+ insertPs .setDate (5 , date , utcCal );
17591765
17601766 int insertStatus2 = insertPs .executeUpdate ();
17611767 assertEquals (1 , insertStatus2 );
17621768
1769+ // Read the stored values server-side so no driver temporal conversion is involved.
17631770 ResultSet rs =
17641771 bigQueryStatement .executeQuery (
1765- String .format ("SELECT COUNT(*) AS row_count\n " + "FROM %s.%s" , DATASET , TABLE_NAME1 ));
1766- rs .next ();
1772+ String .format (
1773+ "SELECT IntegerField, UNIX_MILLIS(TimestampField), CAST(TimeField AS STRING),"
1774+ + " CAST(DateField AS STRING) FROM %s.%s ORDER BY IntegerField" ,
1775+ DATASET , TABLE_NAME1 ));
1776+
1777+ assertTrue (rs .next ());
1778+ assertEquals (1 , rs .getInt (1 ));
1779+ long plainTimestamp = rs .getLong (2 );
1780+ String plainTime = rs .getString (3 );
1781+ String plainDate = rs .getString (4 );
1782+ assertTrue (rs .next ());
17671783 assertEquals (2 , rs .getInt (1 ));
1784+ long calTimestamp = rs .getLong (2 );
1785+ String calTime = rs .getString (3 );
1786+ String calDate = rs .getString (4 );
1787+ assertFalse (rs .next ());
17681788
1789+ // Drop before asserting so a failure does not leak the table.
17691790 String dropQuery = String .format ("DROP TABLE %s.%s" , DATASET , TABLE_NAME1 );
17701791 int dropStatus = bigQueryStatement .executeUpdate (dropQuery );
17711792 assertEquals (0 , dropStatus );
1793+
1794+ assertAll (
1795+ // Row 1: plain setters.
1796+ () ->
1797+ assertEquals (
1798+ moment .toEpochMilli (), plainTimestamp , "setTimestamp must store the moment" ),
1799+ () -> assertEquals ("12:00:00" , plainTime , "setTime must send its digits" ),
1800+ () -> assertEquals ("2025-12-03" , plainDate , "setDate must send its digits" ),
1801+ // Row 2: Calendar setters. The Calendar cannot change a TIMESTAMP moment; for TIME and DATE
1802+ // it is the zone the value is rendered in.
1803+ () ->
1804+ assertEquals (
1805+ moment .toEpochMilli (), calTimestamp , "setTimestamp(ts, cal) must store the moment" ),
1806+ () ->
1807+ assertEquals (
1808+ Instant .ofEpochMilli (noon .getTime ())
1809+ .atZone (ZoneOffset .UTC )
1810+ .format (DateTimeFormatter .ofPattern ("HH:mm:ss" )),
1811+ calTime ,
1812+ "setTime(t, cal) must send the time of t in the Calendar's zone" ),
1813+ () ->
1814+ assertEquals (
1815+ Instant .ofEpochMilli (date .getTime ())
1816+ .atZone (ZoneOffset .UTC )
1817+ .toLocalDate ()
1818+ .toString (),
1819+ calDate ,
1820+ "setDate(d, cal) must send the date of d in the Calendar's zone" ));
17721821 }
17731822
17741823 @ Test
0 commit comments