From 06386e365900c25092f27b92fe4f6f07bd6125c7 Mon Sep 17 00:00:00 2001 From: Praful Makani Date: Sat, 16 Feb 2019 02:43:16 +0530 Subject: [PATCH 1/2] Fixes Bigquery Timestamp --- .../cloud/bigquery/QueryParameterValue.java | 20 ++++++++- .../bigquery/QueryParameterValueTest.java | 42 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java index 5bf6b4e9f93a..cd7f7ddd49d9 100644 --- a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java +++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java @@ -30,7 +30,9 @@ import org.threeten.bp.Instant; import org.threeten.bp.ZoneOffset; import org.threeten.bp.format.DateTimeFormatter; +import org.threeten.bp.format.DateTimeFormatterBuilder; import org.threeten.bp.format.DateTimeParseException; +import org.threeten.bp.temporal.ChronoField; /** * A value for a QueryParameter along with its type. @@ -60,6 +62,21 @@ @AutoValue public abstract class QueryParameterValue implements Serializable { + private static final DateTimeFormatter timestampValidator = + new DateTimeFormatterBuilder() + .parseLenient() + .append(DateTimeFormatter.ISO_LOCAL_DATE) + .appendLiteral(' ') + .append(DateTimeFormatter.ISO_LOCAL_TIME) + .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true) + .optionalStart() + .appendOffsetId() + .optionalEnd() + .optionalStart() + .appendOffset("+HHMM", "Z") + .optionalEnd() + .toFormatter() + .withZone(ZoneOffset.UTC); private static final DateTimeFormatter timestampFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSxxx").withZone(ZoneOffset.UTC); private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); @@ -301,7 +318,7 @@ private static String valueToStringOrNull(T value, StandardSQLTypeName type) return timestampFormatter.format(Instant.ofEpochMilli(((Long) value) / 1000)); } else if (value instanceof String) { // verify that the String is in the right format - checkFormat(value, timestampFormatter); + checkFormat(value, timestampValidator); return (String) value; } break; @@ -335,6 +352,7 @@ private static String valueToStringOrNull(T value, StandardSQLTypeName type) private static void checkFormat(Object value, DateTimeFormatter formatter) { try { + formatter.parse((String) value); } catch (DateTimeParseException e) { throw new IllegalArgumentException(e.getMessage(), e); diff --git a/google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java b/google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java index 485b81e5e497..9d4ea478f24a 100644 --- a/google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java +++ b/google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java @@ -189,6 +189,25 @@ public void testTimestamp() { assertThat(value.getArrayValues()).isNull(); } + @Test + public void testTimestampWithDateTimeFormatterBuilder() { + QueryParameterValue value = QueryParameterValue.timestamp("2019-02-14 12:34:45.938993Z"); + assertThat(value.getValue()).isEqualTo("2019-02-14 12:34:45.938993Z"); + assertThat(value.getType()).isEqualTo(StandardSQLTypeName.TIMESTAMP); + assertThat(value.getArrayType()).isNull(); + assertThat(value.getArrayValues()).isNull(); + QueryParameterValue value1 = QueryParameterValue.timestamp("2019-02-14 12:34:45.938993+0000"); + assertThat(value1.getValue()).isEqualTo("2019-02-14 12:34:45.938993+0000"); + assertThat(value1.getType()).isEqualTo(StandardSQLTypeName.TIMESTAMP); + assertThat(value1.getArrayType()).isNull(); + assertThat(value1.getArrayValues()).isNull(); + QueryParameterValue value2 = QueryParameterValue.timestamp("2019-02-14 12:34:45.102+00:00"); + assertThat(value2.getValue()).isEqualTo("2019-02-14 12:34:45.102+00:00"); + assertThat(value2.getType()).isEqualTo(StandardSQLTypeName.TIMESTAMP); + assertThat(value2.getArrayType()).isNull(); + assertThat(value2.getArrayValues()).isNull(); + } + @Test(expected = IllegalArgumentException.class) public void testInvalidTimestamp() { // missing the time @@ -269,6 +288,29 @@ public void testTimestampArray() { value.getArrayValues()); } + @Test + public void testTimestampArrayWithDateTimeFormatterBuilder() { + QueryParameterValue value = + QueryParameterValue.array( + new String[] { + "2019-02-14 12:34:45.938993Z", + "2019-02-14 12:34:45.938993+0000", + "2019-02-14 12:34:45.102+00:00" + }, + StandardSQLTypeName.TIMESTAMP); + assertThat(value.getValue()).isNull(); + assertThat(value.getType()).isEqualTo(StandardSQLTypeName.ARRAY); + assertThat(value.getArrayType()).isEqualTo(StandardSQLTypeName.TIMESTAMP); + assertArrayDataEquals( + new String[] { + "2019-02-14 12:34:45.938993Z", + "2019-02-14 12:34:45.938993+0000", + "2019-02-14 12:34:45.102+00:00" + }, + StandardSQLTypeName.TIMESTAMP, + value.getArrayValues()); + } + @Test public void testFromEmptyArray() { QueryParameterType typePb = From 2387727b751d09ff0e4fb5ded2da03fe1c7b6b8c Mon Sep 17 00:00:00 2001 From: Praful Makani Date: Tue, 19 Feb 2019 22:52:48 +0530 Subject: [PATCH 2/2] modified code --- .../cloud/bigquery/QueryParameterValue.java | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java index cd7f7ddd49d9..7f1f07754b57 100644 --- a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java +++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java @@ -16,6 +16,11 @@ package com.google.cloud.bigquery; +import static org.threeten.bp.temporal.ChronoField.HOUR_OF_DAY; +import static org.threeten.bp.temporal.ChronoField.MINUTE_OF_HOUR; +import static org.threeten.bp.temporal.ChronoField.NANO_OF_SECOND; +import static org.threeten.bp.temporal.ChronoField.SECOND_OF_MINUTE; + import com.google.api.services.bigquery.model.QueryParameterType; import com.google.auto.value.AutoValue; import com.google.common.base.Function; @@ -32,7 +37,6 @@ import org.threeten.bp.format.DateTimeFormatter; import org.threeten.bp.format.DateTimeFormatterBuilder; import org.threeten.bp.format.DateTimeParseException; -import org.threeten.bp.temporal.ChronoField; /** * A value for a QueryParameter along with its type. @@ -62,23 +66,33 @@ @AutoValue public abstract class QueryParameterValue implements Serializable { - private static final DateTimeFormatter timestampValidator = + private static final DateTimeFormatter timestampFormatter = new DateTimeFormatterBuilder() .parseLenient() .append(DateTimeFormatter.ISO_LOCAL_DATE) .appendLiteral(' ') - .append(DateTimeFormatter.ISO_LOCAL_TIME) - .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true) + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) .optionalStart() - .appendOffsetId() + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .optionalStart() + .appendFraction(NANO_OF_SECOND, 6, 9, true) + .optionalStart() + .appendOffset("+HHMM", "+00:00") .optionalEnd() + .toFormatter() + .withZone(ZoneOffset.UTC); + private static final DateTimeFormatter timestampValidator = + new DateTimeFormatterBuilder() + .parseLenient() + .append(timestampFormatter) .optionalStart() - .appendOffset("+HHMM", "Z") + .appendOffsetId() .optionalEnd() .toFormatter() .withZone(ZoneOffset.UTC); - private static final DateTimeFormatter timestampFormatter = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSxxx").withZone(ZoneOffset.UTC); private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS");