|
16 | 16 |
|
17 | 17 | package com.google.cloud.bigquery; |
18 | 18 |
|
| 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 | + |
19 | 24 | import com.google.api.services.bigquery.model.QueryParameterType; |
20 | 25 | import com.google.auto.value.AutoValue; |
21 | 26 | import com.google.common.base.Function; |
|
31 | 36 | import org.threeten.bp.Instant; |
32 | 37 | import org.threeten.bp.ZoneOffset; |
33 | 38 | import org.threeten.bp.format.DateTimeFormatter; |
| 39 | +import org.threeten.bp.format.DateTimeFormatterBuilder; |
34 | 40 | import org.threeten.bp.format.DateTimeParseException; |
35 | 41 |
|
36 | 42 | /** |
|
62 | 68 | public abstract class QueryParameterValue implements Serializable { |
63 | 69 |
|
64 | 70 | 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); |
66 | 97 | private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
67 | 98 | private static final DateTimeFormatter timeFormatter = |
68 | 99 | DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS"); |
@@ -304,7 +335,7 @@ private static <T> String valueToStringOrNull(T value, StandardSQLTypeName type) |
304 | 335 | return timestampFormatter.format(Instant.ofEpochMilli(((Long) value) / 1000)); |
305 | 336 | } else if (value instanceof String) { |
306 | 337 | // verify that the String is in the right format |
307 | | - checkFormat(value, timestampFormatter); |
| 338 | + checkFormat(value, timestampValidator); |
308 | 339 | return (String) value; |
309 | 340 | } |
310 | 341 | break; |
@@ -341,6 +372,7 @@ private static <T> String valueToStringOrNull(T value, StandardSQLTypeName type) |
341 | 372 |
|
342 | 373 | private static void checkFormat(Object value, DateTimeFormatter formatter) { |
343 | 374 | try { |
| 375 | + |
344 | 376 | formatter.parse((String) value); |
345 | 377 | } catch (DateTimeParseException e) { |
346 | 378 | throw new IllegalArgumentException(e.getMessage(), e); |
|
0 commit comments