Skip to content

Commit 7a6aa23

Browse files
Praful Makanisduskis
authored andcommitted
BigQuery: Fix timestamp parsing regression (#4510)
* Fixes Bigquery Timestamp * modified code
1 parent b7fc66d commit 7a6aa23

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
package com.google.cloud.bigquery;
1818

19+
import static org.threeten.bp.temporal.ChronoField.HOUR_OF_DAY;
20+
import static org.threeten.bp.temporal.ChronoField.MINUTE_OF_HOUR;
21+
import static org.threeten.bp.temporal.ChronoField.NANO_OF_SECOND;
22+
import static org.threeten.bp.temporal.ChronoField.SECOND_OF_MINUTE;
23+
1924
import com.google.api.services.bigquery.model.QueryParameterType;
2025
import com.google.auto.value.AutoValue;
2126
import com.google.common.base.Function;
@@ -31,6 +36,7 @@
3136
import org.threeten.bp.Instant;
3237
import org.threeten.bp.ZoneOffset;
3338
import org.threeten.bp.format.DateTimeFormatter;
39+
import org.threeten.bp.format.DateTimeFormatterBuilder;
3440
import org.threeten.bp.format.DateTimeParseException;
3541

3642
/**
@@ -62,7 +68,32 @@
6268
public abstract class QueryParameterValue implements Serializable {
6369

6470
private static final DateTimeFormatter timestampFormatter =
65-
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSxxx").withZone(ZoneOffset.UTC);
71+
new DateTimeFormatterBuilder()
72+
.parseLenient()
73+
.append(DateTimeFormatter.ISO_LOCAL_DATE)
74+
.appendLiteral(' ')
75+
.appendValue(HOUR_OF_DAY, 2)
76+
.appendLiteral(':')
77+
.appendValue(MINUTE_OF_HOUR, 2)
78+
.optionalStart()
79+
.appendLiteral(':')
80+
.appendValue(SECOND_OF_MINUTE, 2)
81+
.optionalStart()
82+
.appendFraction(NANO_OF_SECOND, 6, 9, true)
83+
.optionalStart()
84+
.appendOffset("+HHMM", "+00:00")
85+
.optionalEnd()
86+
.toFormatter()
87+
.withZone(ZoneOffset.UTC);
88+
private static final DateTimeFormatter timestampValidator =
89+
new DateTimeFormatterBuilder()
90+
.parseLenient()
91+
.append(timestampFormatter)
92+
.optionalStart()
93+
.appendOffsetId()
94+
.optionalEnd()
95+
.toFormatter()
96+
.withZone(ZoneOffset.UTC);
6697
private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
6798
private static final DateTimeFormatter timeFormatter =
6899
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS");
@@ -304,7 +335,7 @@ private static <T> String valueToStringOrNull(T value, StandardSQLTypeName type)
304335
return timestampFormatter.format(Instant.ofEpochMilli(((Long) value) / 1000));
305336
} else if (value instanceof String) {
306337
// verify that the String is in the right format
307-
checkFormat(value, timestampFormatter);
338+
checkFormat(value, timestampValidator);
308339
return (String) value;
309340
}
310341
break;
@@ -341,6 +372,7 @@ private static <T> String valueToStringOrNull(T value, StandardSQLTypeName type)
341372

342373
private static void checkFormat(Object value, DateTimeFormatter formatter) {
343374
try {
375+
344376
formatter.parse((String) value);
345377
} catch (DateTimeParseException e) {
346378
throw new IllegalArgumentException(e.getMessage(), e);

google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,25 @@ public void testTimestamp() {
191191
assertThat(value.getArrayValues()).isNull();
192192
}
193193

194+
@Test
195+
public void testTimestampWithDateTimeFormatterBuilder() {
196+
QueryParameterValue value = QueryParameterValue.timestamp("2019-02-14 12:34:45.938993Z");
197+
assertThat(value.getValue()).isEqualTo("2019-02-14 12:34:45.938993Z");
198+
assertThat(value.getType()).isEqualTo(StandardSQLTypeName.TIMESTAMP);
199+
assertThat(value.getArrayType()).isNull();
200+
assertThat(value.getArrayValues()).isNull();
201+
QueryParameterValue value1 = QueryParameterValue.timestamp("2019-02-14 12:34:45.938993+0000");
202+
assertThat(value1.getValue()).isEqualTo("2019-02-14 12:34:45.938993+0000");
203+
assertThat(value1.getType()).isEqualTo(StandardSQLTypeName.TIMESTAMP);
204+
assertThat(value1.getArrayType()).isNull();
205+
assertThat(value1.getArrayValues()).isNull();
206+
QueryParameterValue value2 = QueryParameterValue.timestamp("2019-02-14 12:34:45.102+00:00");
207+
assertThat(value2.getValue()).isEqualTo("2019-02-14 12:34:45.102+00:00");
208+
assertThat(value2.getType()).isEqualTo(StandardSQLTypeName.TIMESTAMP);
209+
assertThat(value2.getArrayType()).isNull();
210+
assertThat(value2.getArrayValues()).isNull();
211+
}
212+
194213
@Test(expected = IllegalArgumentException.class)
195214
public void testInvalidTimestamp() {
196215
// missing the time
@@ -282,6 +301,29 @@ public void testTimestampArray() {
282301
value.getArrayValues());
283302
}
284303

304+
@Test
305+
public void testTimestampArrayWithDateTimeFormatterBuilder() {
306+
QueryParameterValue value =
307+
QueryParameterValue.array(
308+
new String[] {
309+
"2019-02-14 12:34:45.938993Z",
310+
"2019-02-14 12:34:45.938993+0000",
311+
"2019-02-14 12:34:45.102+00:00"
312+
},
313+
StandardSQLTypeName.TIMESTAMP);
314+
assertThat(value.getValue()).isNull();
315+
assertThat(value.getType()).isEqualTo(StandardSQLTypeName.ARRAY);
316+
assertThat(value.getArrayType()).isEqualTo(StandardSQLTypeName.TIMESTAMP);
317+
assertArrayDataEquals(
318+
new String[] {
319+
"2019-02-14 12:34:45.938993Z",
320+
"2019-02-14 12:34:45.938993+0000",
321+
"2019-02-14 12:34:45.102+00:00"
322+
},
323+
StandardSQLTypeName.TIMESTAMP,
324+
value.getArrayValues());
325+
}
326+
285327
@Test
286328
public void testFromEmptyArray() {
287329
QueryParameterType typePb =

0 commit comments

Comments
 (0)