From 6bc4b42b58150230434ad3227bfc02d472fd3aab Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 22 Apr 2026 13:24:07 -0400 Subject: [PATCH 1/7] test(bigquery): Add tests to verify lossless max timestamp parsing --- .../google/cloud/bigquery/FieldValueTest.java | 12 ++++++++++ .../cloud/bigquery/it/ITBigQueryTest.java | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldValueTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldValueTest.java index 958e20659868..e6b08ec6b8a3 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldValueTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldValueTest.java @@ -151,6 +151,18 @@ public void testInt64Timestamp() { assertEquals(expected, received); } + @Test + public void testLosslessMaxTimestamp() { + // Test the lossless behavior (useInt64Timestamps = true) + // The backend returns a 64-bit integer string for microseconds when this option is enabled + String losslessTimestampString = "253402300799999999"; + FieldValue losslessValue = + FieldValue.of(FieldValue.Attribute.PRIMITIVE, losslessTimestampString, true); + + // Exactly matches the microsecond equivalent of 9999-12-31 23:59:59.999999 + assertEquals(253402300799999999L, losslessValue.getTimestampValue()); + } + @Test public void testEquals() { FieldValue booleanValue = FieldValue.of(FieldValue.Attribute.PRIMITIVE, "false"); diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index b7bfe586f022..fb82810b9153 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -1215,6 +1215,29 @@ static GoogleCredentials loadCredentials(String credentialFile) { } } + @Test + public void testLosslessMaxTimestampIntegration() throws InterruptedException { + // 1. Initialize BigQueryOptions with the lossless timestamp flag enabled + // We use RemoteBigQueryHelper to get standard test environment credentials + BigQueryOptions options = RemoteBigQueryHelper.create().getOptions().toBuilder() + .setUseInt64Timestamps(true) + .build(); + BigQuery bigquery = options.getService(); + + // 2. Query the absolute maximum timestamp directly from BigQuery + String query = "SELECT TIMESTAMP '9999-12-31 23:59:59.999999 UTC' as max_ts"; + QueryJobConfiguration config = QueryJobConfiguration.newBuilder(query).build(); + + // 3. Execute the query + TableResult result = bigquery.query(config); + + // 4. Verify that the parsed value exactly matches the 64-bit microsecond value without rounding + for (FieldValueList row : result.iterateAll()) { + long exactMicros = row.get("max_ts").getTimestampValue(); + assertEquals(253402300799999999L, exactMicros); + } + } + @Test void testListDatasets() { Page datasets = bigquery.listDatasets("bigquery-public-data"); From df5c66370bfc59a24175c500e48983360e26dae9 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 22 Apr 2026 13:30:22 -0400 Subject: [PATCH 2/7] Update java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index fb82810b9153..d15fffdf5c18 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -1216,7 +1216,7 @@ static GoogleCredentials loadCredentials(String credentialFile) { } @Test - public void testLosslessMaxTimestampIntegration() throws InterruptedException { + void testLosslessMaxTimestampIntegration() throws InterruptedException { // 1. Initialize BigQueryOptions with the lossless timestamp flag enabled // We use RemoteBigQueryHelper to get standard test environment credentials BigQueryOptions options = RemoteBigQueryHelper.create().getOptions().toBuilder() From 31a318729e27d606019a4a79eb9bead9c4b0678a Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 22 Apr 2026 13:30:45 -0400 Subject: [PATCH 3/7] Update java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../java/com/google/cloud/bigquery/it/ITBigQueryTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index d15fffdf5c18..23f4b7d8587d 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -1219,17 +1219,17 @@ static GoogleCredentials loadCredentials(String credentialFile) { void testLosslessMaxTimestampIntegration() throws InterruptedException { // 1. Initialize BigQueryOptions with the lossless timestamp flag enabled // We use RemoteBigQueryHelper to get standard test environment credentials - BigQueryOptions options = RemoteBigQueryHelper.create().getOptions().toBuilder() + BigQueryOptions options = bigquery.getOptions().toBuilder() .setUseInt64Timestamps(true) .build(); - BigQuery bigquery = options.getService(); + BigQuery losslessBigQuery = options.getService(); // 2. Query the absolute maximum timestamp directly from BigQuery String query = "SELECT TIMESTAMP '9999-12-31 23:59:59.999999 UTC' as max_ts"; QueryJobConfiguration config = QueryJobConfiguration.newBuilder(query).build(); // 3. Execute the query - TableResult result = bigquery.query(config); + TableResult result = losslessBigQuery.query(config); // 4. Verify that the parsed value exactly matches the 64-bit microsecond value without rounding for (FieldValueList row : result.iterateAll()) { From 5b461aac562347c3bac8973f6da88f78c44fbb3b Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 22 Apr 2026 13:30:55 -0400 Subject: [PATCH 4/7] Update java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index 23f4b7d8587d..d439cd7adcc8 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -1232,6 +1232,7 @@ void testLosslessMaxTimestampIntegration() throws InterruptedException { TableResult result = losslessBigQuery.query(config); // 4. Verify that the parsed value exactly matches the 64-bit microsecond value without rounding + assertEquals(1L, result.getTotalRows()); for (FieldValueList row : result.iterateAll()) { long exactMicros = row.get("max_ts").getTimestampValue(); assertEquals(253402300799999999L, exactMicros); From dd1a5d20ca0cb133b2961578f8d6a7b97064371a Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 22 Apr 2026 13:35:26 -0400 Subject: [PATCH 5/7] lint --- .../java/com/google/cloud/bigquery/it/ITBigQueryTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index d439cd7adcc8..31845a21d743 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -1219,15 +1219,13 @@ static GoogleCredentials loadCredentials(String credentialFile) { void testLosslessMaxTimestampIntegration() throws InterruptedException { // 1. Initialize BigQueryOptions with the lossless timestamp flag enabled // We use RemoteBigQueryHelper to get standard test environment credentials - BigQueryOptions options = bigquery.getOptions().toBuilder() - .setUseInt64Timestamps(true) - .build(); + BigQueryOptions options = bigquery.getOptions().toBuilder().setUseInt64Timestamps(true).build(); BigQuery losslessBigQuery = options.getService(); // 2. Query the absolute maximum timestamp directly from BigQuery String query = "SELECT TIMESTAMP '9999-12-31 23:59:59.999999 UTC' as max_ts"; QueryJobConfiguration config = QueryJobConfiguration.newBuilder(query).build(); - + // 3. Execute the query TableResult result = losslessBigQuery.query(config); From 9b7414153f100e4b1afd03f1bfba22ec9ef85f51 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 22 Apr 2026 14:48:04 -0400 Subject: [PATCH 6/7] PR feedback --- .../cloud/bigquery/it/ITBigQueryTest.java | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index 31845a21d743..e7135fb49067 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -1217,24 +1217,53 @@ static GoogleCredentials loadCredentials(String credentialFile) { @Test void testLosslessMaxTimestampIntegration() throws InterruptedException { - // 1. Initialize BigQueryOptions with the lossless timestamp flag enabled - // We use RemoteBigQueryHelper to get standard test environment credentials - BigQueryOptions options = bigquery.getOptions().toBuilder().setUseInt64Timestamps(true).build(); - BigQuery losslessBigQuery = options.getService(); - - // 2. Query the absolute maximum timestamp directly from BigQuery String query = "SELECT TIMESTAMP '9999-12-31 23:59:59.999999 UTC' as max_ts"; QueryJobConfiguration config = QueryJobConfiguration.newBuilder(query).build(); - // 3. Execute the query - TableResult result = losslessBigQuery.query(config); - - // 4. Verify that the parsed value exactly matches the 64-bit microsecond value without rounding - assertEquals(1L, result.getTotalRows()); - for (FieldValueList row : result.iterateAll()) { + // 1. Test lossless 64-bit integer parsing (useInt64Timestamps = true) + DataFormatOptions losslessOptions = DataFormatOptions.newBuilder() + .useInt64Timestamp(true) + .build(); + BigQuery losslessBigQuery = bigquery.getOptions().toBuilder() + .setDataFormatOptions(losslessOptions) + .build().getService(); + + TableResult losslessResult = losslessBigQuery.query(config); + assertEquals(1L, losslessResult.getTotalRows()); + for (FieldValueList row : losslessResult.iterateAll()) { long exactMicros = row.get("max_ts").getTimestampValue(); assertEquals(253402300799999999L, exactMicros); } + + // 2. Test lossy FLOAT64 rounding behavior (useInt64Timestamps = false) + DataFormatOptions floatOptions = DataFormatOptions.newBuilder() + .useInt64Timestamp(false) + .build(); + BigQuery floatBigQuery = bigquery.getOptions().toBuilder() + .setDataFormatOptions(floatOptions) + .build().getService(); + + TableResult floatResult = floatBigQuery.query(config); + assertEquals(1L, floatResult.getTotalRows()); + for (FieldValueList row : floatResult.iterateAll()) { + long roundedMicros = row.get("max_ts").getTimestampValue(); + assertEquals(253402300800000000L, roundedMicros); + } + + // 3. Test ISO8601 timestamp formatting + DataFormatOptions isoOptions = DataFormatOptions.newBuilder() + .timestampFormatOptions(DataFormatOptions.TimestampFormatOptions.ISO8601_STRING) + .build(); + BigQuery isoBigQuery = bigquery.getOptions().toBuilder() + .setDataFormatOptions(isoOptions) + .build().getService(); + + TableResult isoResult = isoBigQuery.query(config); + assertEquals(1L, isoResult.getTotalRows()); + for (FieldValueList row : isoResult.iterateAll()) { + String isoValue = row.get("max_ts").getStringValue(); + assertEquals("9999-12-31T23:59:59.999999Z", isoValue); + } } @Test From b19bb2e8965c28cbaaa8df1fe4ad8cad24781947 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 22 Apr 2026 14:54:19 -0400 Subject: [PATCH 7/7] lint --- .../cloud/bigquery/it/ITBigQueryTest.java | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index e7135fb49067..3185354364d2 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -1221,12 +1221,13 @@ void testLosslessMaxTimestampIntegration() throws InterruptedException { QueryJobConfiguration config = QueryJobConfiguration.newBuilder(query).build(); // 1. Test lossless 64-bit integer parsing (useInt64Timestamps = true) - DataFormatOptions losslessOptions = DataFormatOptions.newBuilder() - .useInt64Timestamp(true) - .build(); - BigQuery losslessBigQuery = bigquery.getOptions().toBuilder() - .setDataFormatOptions(losslessOptions) - .build().getService(); + DataFormatOptions losslessOptions = + DataFormatOptions.newBuilder().useInt64Timestamp(true).build(); + BigQuery losslessBigQuery = + bigquery.getOptions().toBuilder() + .setDataFormatOptions(losslessOptions) + .build() + .getService(); TableResult losslessResult = losslessBigQuery.query(config); assertEquals(1L, losslessResult.getTotalRows()); @@ -1236,12 +1237,10 @@ void testLosslessMaxTimestampIntegration() throws InterruptedException { } // 2. Test lossy FLOAT64 rounding behavior (useInt64Timestamps = false) - DataFormatOptions floatOptions = DataFormatOptions.newBuilder() - .useInt64Timestamp(false) - .build(); - BigQuery floatBigQuery = bigquery.getOptions().toBuilder() - .setDataFormatOptions(floatOptions) - .build().getService(); + DataFormatOptions floatOptions = + DataFormatOptions.newBuilder().useInt64Timestamp(false).build(); + BigQuery floatBigQuery = + bigquery.getOptions().toBuilder().setDataFormatOptions(floatOptions).build().getService(); TableResult floatResult = floatBigQuery.query(config); assertEquals(1L, floatResult.getTotalRows()); @@ -1251,12 +1250,12 @@ void testLosslessMaxTimestampIntegration() throws InterruptedException { } // 3. Test ISO8601 timestamp formatting - DataFormatOptions isoOptions = DataFormatOptions.newBuilder() - .timestampFormatOptions(DataFormatOptions.TimestampFormatOptions.ISO8601_STRING) - .build(); - BigQuery isoBigQuery = bigquery.getOptions().toBuilder() - .setDataFormatOptions(isoOptions) - .build().getService(); + DataFormatOptions isoOptions = + DataFormatOptions.newBuilder() + .timestampFormatOptions(DataFormatOptions.TimestampFormatOptions.ISO8601_STRING) + .build(); + BigQuery isoBigQuery = + bigquery.getOptions().toBuilder().setDataFormatOptions(isoOptions).build().getService(); TableResult isoResult = isoBigQuery.query(config); assertEquals(1L, isoResult.getTotalRows());