Skip to content

fix(bigquery-jdbc): preserve civil digits for DATETIME/DATE - #14910

Open
keshavdandeva wants to merge 1 commit into
mainfrom
jdbc/fix-dst-for-datetime
Open

keshavdandeva wants to merge 1 commit into
mainfrom
jdbc/fix-dst-for-datetime

Conversation

@keshavdandeva

Copy link
Copy Markdown
Contributor

b/577457022

Summary

Prevents JVM default timezone DST gaps and historical calendar shifts from corrupting timezone-less civil temporal types (DATETIME, DATE, TIME) when accessed as java.sql.Date, java.sql.Time, or formatted inside ARRAY and STRUCT.

Root Cause

  1. Date / Time extraction from DATETIME: BigQueryBaseResultSet (getDate, getTime, getObject(int, Class)) and BigQueryTypeRegistry (createDatetimeDescriptor) boxed DATETIME values into an intermediate java.sql.Timestamp in the JVM default timezone before extracting Date or Time. When a DATETIME value fell inside a local DST spring-forward gap (e.g., 2025-03-09 02:30:00 in America/New_York), the intermediate Timestamp shifted the wall-clock hour forward by +1 hour (03:30:00).
  2. ARRAY / STRUCT string formatting: BigQueryBaseArray.toString() and BigQueryBaseStruct.appendJsonValue() called .toString() on boxed java.sql.Timestamp / java.sql.Date elements, corrupting ARRAY<DATETIME> / STRUCT<DATETIME> values in DST gaps and ARRAY<DATE> / STRUCT<DATE> values prior to the 1582 Julian–Gregorian cutover.

Changes

  • BigQueryTemporalUtility: Added isCivilTemporalType and formatCivilTemporalElement to centralize civil type checks and format raw DATE, TIME, and DATETIME elements directly from their unshifted civil representation.
  • BigQueryTypeRegistry: Unified createDatetimeDescriptor to parse DATETIME into LocalDateTime once and project directly to Date, Time, LocalDate, LocalTime, LocalDateTime, String, or instant views without intermediate Timestamp boxing.
  • BigQueryBaseResultSet: Updated getObject, getDate, getTime, and getTimestamp to pass raw unboxed values for civil temporal types (DATE, TIME, DATETIME) to BigQueryTypeRegistry.
  • BigQueryBaseArray & BigQueryBaseStruct: Updated string/JSON formatting to format civil temporal elements directly from raw values via BigQueryTemporalUtility.formatCivilTemporalElement.

@keshavdandeva
keshavdandeva requested review from a team as code owners November 3, 2026 18:23

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the handling of civil temporal types (DATE, TIME, and DATETIME) in the BigQuery JDBC driver to prevent timezone conversion issues, particularly during Daylight Saving Time (DST) gaps. It introduces utility methods in BigQueryTemporalUtility to format civil temporal elements for complex types like arrays and structs without boxing them through java.sql types, and simplifies retrieval logic in BigQueryBaseResultSet and BigQueryTypeRegistry. The review feedback highlights a critical issue in the new unit test testDatetimeReadCoercionsPreserveCivilDigits where the JVM-wide default timezone is modified without being restored, which could lead to test pollution and flaky tests.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant