From 3166b8ef3222c706cbae45312e626c592a74c470 Mon Sep 17 00:00:00 2001 From: Marios Trivyzas Date: Sat, 8 Feb 2020 16:03:09 +0100 Subject: [PATCH] SQL: Enhance timestamp escaped literal parsing Allow also whitespace ` ` (together with `T`) as a separator between date and time parts of the timestamp string. E.g.: ``` 2020-02-08 12.10.45 ``` or ``` 2020-02-08T12.10.45 ``` Fixes: #46049 --- .../xpack/sql/util/DateUtils.java | 22 ++++++++++++++----- .../sql/parser/EscapedFunctionsTests.java | 10 ++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/util/DateUtils.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/util/DateUtils.java index 448b6bc537602..56d6daeaddab4 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/util/DateUtils.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/util/DateUtils.java @@ -20,6 +20,7 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; import static java.time.format.DateTimeFormatter.ISO_LOCAL_TIME; @@ -32,11 +33,16 @@ public final class DateUtils { public static final LocalDate EPOCH = LocalDate.of(1970, 1, 1); public static final long DAY_IN_MILLIS = 60 * 60 * 24 * 1000L; - private static final DateTimeFormatter DATE_TIME_ESCAPED_LITERAL_FORMATTER = new DateTimeFormatterBuilder() - .append(ISO_LOCAL_DATE) - .appendLiteral(" ") - .append(ISO_LOCAL_TIME) - .toFormatter().withZone(UTC); + private static final DateTimeFormatter DATE_TIME_ESCAPED_LITERAL_FORMATTER_WHITESPACE = new DateTimeFormatterBuilder() + .append(ISO_LOCAL_DATE) + .appendLiteral(" ") + .append(ISO_LOCAL_TIME) + .toFormatter().withZone(UTC); + private static final DateTimeFormatter DATE_TIME_ESCAPED_LITERAL_FORMATTER_T_LITERAL = new DateTimeFormatterBuilder() + .append(ISO_LOCAL_DATE) + .appendLiteral("T") + .append(ISO_LOCAL_TIME) + .toFormatter().withZone(UTC); private static final DateFormatter UTC_DATE_TIME_FORMATTER = DateFormatter.forPattern("date_optional_time").withZone(UTC); private static final int DEFAULT_PRECISION_FOR_CURRENT_FUNCTIONS = 3; @@ -105,7 +111,11 @@ public static ZonedDateTime asDateTime(String dateFormat) { } public static ZonedDateTime ofEscapedLiteral(String dateFormat) { - return ZonedDateTime.parse(dateFormat, DATE_TIME_ESCAPED_LITERAL_FORMATTER.withZone(UTC)); + try { + return ZonedDateTime.parse(dateFormat, DATE_TIME_ESCAPED_LITERAL_FORMATTER_T_LITERAL.withZone(UTC)); + } catch (DateTimeParseException e) { + return ZonedDateTime.parse(dateFormat, DATE_TIME_ESCAPED_LITERAL_FORMATTER_WHITESPACE.withZone(UTC)); + } } public static String toString(ZonedDateTime dateTime) { diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/EscapedFunctionsTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/EscapedFunctionsTests.java index 2852619edb004..f69e00cf83488 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/EscapedFunctionsTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/EscapedFunctionsTests.java @@ -209,14 +209,18 @@ public void testTimeLiteralValidation() { } public void testTimestampLiteral() { - Literal l = timestampLiteral("2012-01-01 10:01:02.3456"); + String fractionalSecs = randomFrom("", ".1", ".12", ".123", ".1234", ".12345", ".123456", + ".1234567", ".12345678", ".123456789"); + Literal l = timestampLiteral("2012-01-01 10:01:02" + fractionalSecs); + assertThat(l.dataType(), is(DATETIME)); + l = timestampLiteral("2012-01-01T10:01:02" + fractionalSecs); assertThat(l.dataType(), is(DATETIME)); } public void testTimestampLiteralValidation() { - ParsingException ex = expectThrows(ParsingException.class, () -> timestampLiteral("2012-01-01T10:01:02.3456")); + ParsingException ex = expectThrows(ParsingException.class, () -> timestampLiteral("2012-01-01_AB 10:01:02.3456")); assertEquals( - "line 1:2: Invalid timestamp received; Text '2012-01-01T10:01:02.3456' could not be parsed at index 10", + "line 1:2: Invalid timestamp received; Text '2012-01-01_AB 10:01:02.3456' could not be parsed at index 10", ex.getMessage()); }