You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 53bbde0
Browse filesBrowse the repository at this point in the historyBrowse files
fix(bigquery-jdbc): preserve civil digits for DATETIME/DATE (#14910)
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`.
0 commit comments