From fc44c89e74bc4877f98067e7fafe3097430a6886 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Thu, 10 Oct 2019 18:05:40 +0200 Subject: [PATCH 1/2] Allow partial parsing dates (#46814) Enable partial parsing of date part. This is making the behaviour in java.time implementation the same as with joda. 2018, 2018-01 and 2018-01-01 are all valid dates for date_optional_time or strict_date_optional_time closes #45284 closes #47473 --- .../common/time/DateFormatters.java | 7 +++- .../joda/JavaJodaTimeDuellingTests.java | 34 +++++++++++++++++++ .../common/time/JavaDateMathParserTests.java | 9 ++--- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/common/time/DateFormatters.java b/server/src/main/java/org/elasticsearch/common/time/DateFormatters.java index 0cd0e9dff78ea..052ecf902ed64 100644 --- a/server/src/main/java/org/elasticsearch/common/time/DateFormatters.java +++ b/server/src/main/java/org/elasticsearch/common/time/DateFormatters.java @@ -40,7 +40,6 @@ import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalQueries; import java.time.temporal.WeekFields; -import java.util.Locale; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.DAY_OF_WEEK; @@ -59,10 +58,14 @@ public class DateFormatters { private static final DateTimeFormatter STRICT_YEAR_MONTH_DAY_FORMATTER = new DateTimeFormatterBuilder() .appendValue(ChronoField.YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .optionalStart() .appendLiteral("-") .appendValue(MONTH_OF_YEAR, 2, 2, SignStyle.NOT_NEGATIVE) + .optionalStart() .appendLiteral('-') .appendValue(DAY_OF_MONTH, 2, 2, SignStyle.NOT_NEGATIVE) + .optionalEnd() + .optionalEnd() .toFormatter(Locale.ROOT); private static final DateTimeFormatter STRICT_HOUR_MINUTE_SECOND_FORMATTER = new DateTimeFormatterBuilder() @@ -910,12 +913,14 @@ public class DateFormatters { private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder() .appendValue(ChronoField.YEAR, 1, 5, SignStyle.NORMAL) + .optionalStart() .appendLiteral('-') .appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NOT_NEGATIVE) .optionalStart() .appendLiteral('-') .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) .optionalEnd() + .optionalEnd() .toFormatter(Locale.ROOT); private static final DateTimeFormatter HOUR_MINUTE_FORMATTER = new DateTimeFormatterBuilder() diff --git a/server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java b/server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java index e686193645fa0..67912ccbbcaf6 100644 --- a/server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java +++ b/server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java @@ -40,8 +40,36 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; +import static org.hamcrest.core.IsEqual.equalTo; public class JavaJodaTimeDuellingTests extends ESTestCase { + @Override + protected boolean enableWarningsCheck() { + return false; + } + // date_optional part of a parser names "strict_date_optional_time" or "date_optional"time + // means that date part can be partially parsed. + public void testPartialParsing() { + assertSameDateAs("2001", "strict_date_optional_time_nanos", "strict_date_optional_time"); + assertSameDateAs("2001-01", "strict_date_optional_time_nanos", "strict_date_optional_time"); + assertSameDateAs("2001-01-01", "strict_date_optional_time_nanos", "strict_date_optional_time"); + + assertSameDate("2001", "strict_date_optional_time"); + assertSameDate("2001-01", "strict_date_optional_time"); + assertSameDate("2001-01-01", "strict_date_optional_time"); + + assertSameDate("2001", "date_optional_time"); + assertSameDate("2001-01", "date_optional_time"); + assertSameDate("2001-01-01", "date_optional_time"); + + + assertSameDateAs("2001", "iso8601", "strict_date_optional_time"); + assertSameDateAs("2001-01", "iso8601", "strict_date_optional_time"); + assertSameDateAs("2001-01-01", "iso8601", "strict_date_optional_time"); + + assertSameDate("9999","date_optional_time||epoch_second"); + } + public void testCompositeDateMathParsing(){ //in all these examples the second pattern will be used assertDateMathEquals("2014-06-06T12:01:02.123", "yyyy-MM-dd'T'HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS"); @@ -909,4 +937,10 @@ private void assertDateMathEquals(String text, String pattern) { assertEquals(gotMillisJoda, gotMillisJava); } + + private void assertSameDateAs(String input, String javaPattern, String jodaPattern) { + DateFormatter javaFormatter = DateFormatter.forPattern(javaPattern); + DateFormatter jodaFormatter = Joda.forPattern(jodaPattern); + assertSameDate(input, javaPattern, jodaFormatter, javaFormatter); + } } diff --git a/server/src/test/java/org/elasticsearch/common/time/JavaDateMathParserTests.java b/server/src/test/java/org/elasticsearch/common/time/JavaDateMathParserTests.java index c50ec185dc5d5..34903e024d05d 100644 --- a/server/src/test/java/org/elasticsearch/common/time/JavaDateMathParserTests.java +++ b/server/src/test/java/org/elasticsearch/common/time/JavaDateMathParserTests.java @@ -258,10 +258,11 @@ public void testTimestamps() { long datetime = parser.parse("1418248078", () -> 0).toEpochMilli(); assertDateEquals(datetime, "1418248078", "2014-12-10T21:47:58.000"); - // a timestamp before 10000 is a year - assertDateMathEquals("9999", "1970-01-01T00:00:09.999Z"); - // 10000 is also a year, breaking bwc, used to be a timestamp - assertDateMathEquals("10000", "1970-01-01T00:00:10.000Z"); + // a timestamp before 100000 is a year + assertDateMathEquals("9999", "9999-01-01T00:00:00.000"); + assertDateMathEquals("10000", "10000-01-01T00:00:00.000"); + assertDateMathEquals("100000", "1970-01-01T00:01:40.000"); + // but 10000 with T is still a date format assertDateMathEquals("10000-01-01T", "10000-01-01T00:00:00.000"); } From d220487b69cf3ae447c61c5b474a28ae262745e4 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Thu, 10 Oct 2019 18:35:02 +0200 Subject: [PATCH 2/2] compile fix --- .../main/java/org/elasticsearch/common/time/DateFormatters.java | 1 + .../org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/common/time/DateFormatters.java b/server/src/main/java/org/elasticsearch/common/time/DateFormatters.java index 052ecf902ed64..5f8edab1e1318 100644 --- a/server/src/main/java/org/elasticsearch/common/time/DateFormatters.java +++ b/server/src/main/java/org/elasticsearch/common/time/DateFormatters.java @@ -40,6 +40,7 @@ import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalQueries; import java.time.temporal.WeekFields; +import java.util.Locale; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.DAY_OF_WEEK; diff --git a/server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java b/server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java index 67912ccbbcaf6..008dc6bce3de0 100644 --- a/server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java +++ b/server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java @@ -38,7 +38,6 @@ import java.util.Locale; import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.core.IsEqual.equalTo;