Skip to content

Commit fc44c89

Browse files
committed
Allow partial parsing dates (elastic#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 elastic#45284 closes elastic#47473
1 parent 59b3294 commit fc44c89

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

server/src/main/java/org/elasticsearch/common/time/DateFormatters.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import java.time.temporal.TemporalAdjusters;
4141
import java.time.temporal.TemporalQueries;
4242
import java.time.temporal.WeekFields;
43-
import java.util.Locale;
4443

4544
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
4645
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
@@ -59,10 +58,14 @@ public class DateFormatters {
5958

6059
private static final DateTimeFormatter STRICT_YEAR_MONTH_DAY_FORMATTER = new DateTimeFormatterBuilder()
6160
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
61+
.optionalStart()
6262
.appendLiteral("-")
6363
.appendValue(MONTH_OF_YEAR, 2, 2, SignStyle.NOT_NEGATIVE)
64+
.optionalStart()
6465
.appendLiteral('-')
6566
.appendValue(DAY_OF_MONTH, 2, 2, SignStyle.NOT_NEGATIVE)
67+
.optionalEnd()
68+
.optionalEnd()
6669
.toFormatter(Locale.ROOT);
6770

6871
private static final DateTimeFormatter STRICT_HOUR_MINUTE_SECOND_FORMATTER = new DateTimeFormatterBuilder()
@@ -910,12 +913,14 @@ public class DateFormatters {
910913

911914
private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder()
912915
.appendValue(ChronoField.YEAR, 1, 5, SignStyle.NORMAL)
916+
.optionalStart()
913917
.appendLiteral('-')
914918
.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NOT_NEGATIVE)
915919
.optionalStart()
916920
.appendLiteral('-')
917921
.appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE)
918922
.optionalEnd()
923+
.optionalEnd()
919924
.toFormatter(Locale.ROOT);
920925

921926
private static final DateTimeFormatter HOUR_MINUTE_FORMATTER = new DateTimeFormatterBuilder()

server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,36 @@
4040
import static org.hamcrest.Matchers.containsString;
4141
import static org.hamcrest.Matchers.equalTo;
4242
import static org.hamcrest.Matchers.is;
43+
import static org.hamcrest.core.IsEqual.equalTo;
4344

4445
public class JavaJodaTimeDuellingTests extends ESTestCase {
46+
@Override
47+
protected boolean enableWarningsCheck() {
48+
return false;
49+
}
50+
// date_optional part of a parser names "strict_date_optional_time" or "date_optional"time
51+
// means that date part can be partially parsed.
52+
public void testPartialParsing() {
53+
assertSameDateAs("2001", "strict_date_optional_time_nanos", "strict_date_optional_time");
54+
assertSameDateAs("2001-01", "strict_date_optional_time_nanos", "strict_date_optional_time");
55+
assertSameDateAs("2001-01-01", "strict_date_optional_time_nanos", "strict_date_optional_time");
56+
57+
assertSameDate("2001", "strict_date_optional_time");
58+
assertSameDate("2001-01", "strict_date_optional_time");
59+
assertSameDate("2001-01-01", "strict_date_optional_time");
60+
61+
assertSameDate("2001", "date_optional_time");
62+
assertSameDate("2001-01", "date_optional_time");
63+
assertSameDate("2001-01-01", "date_optional_time");
64+
65+
66+
assertSameDateAs("2001", "iso8601", "strict_date_optional_time");
67+
assertSameDateAs("2001-01", "iso8601", "strict_date_optional_time");
68+
assertSameDateAs("2001-01-01", "iso8601", "strict_date_optional_time");
69+
70+
assertSameDate("9999","date_optional_time||epoch_second");
71+
}
72+
4573
public void testCompositeDateMathParsing(){
4674
//in all these examples the second pattern will be used
4775
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) {
909937

910938
assertEquals(gotMillisJoda, gotMillisJava);
911939
}
940+
941+
private void assertSameDateAs(String input, String javaPattern, String jodaPattern) {
942+
DateFormatter javaFormatter = DateFormatter.forPattern(javaPattern);
943+
DateFormatter jodaFormatter = Joda.forPattern(jodaPattern);
944+
assertSameDate(input, javaPattern, jodaFormatter, javaFormatter);
945+
}
912946
}

server/src/test/java/org/elasticsearch/common/time/JavaDateMathParserTests.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,11 @@ public void testTimestamps() {
258258
long datetime = parser.parse("1418248078", () -> 0).toEpochMilli();
259259
assertDateEquals(datetime, "1418248078", "2014-12-10T21:47:58.000");
260260

261-
// a timestamp before 10000 is a year
262-
assertDateMathEquals("9999", "1970-01-01T00:00:09.999Z");
263-
// 10000 is also a year, breaking bwc, used to be a timestamp
264-
assertDateMathEquals("10000", "1970-01-01T00:00:10.000Z");
261+
// a timestamp before 100000 is a year
262+
assertDateMathEquals("9999", "9999-01-01T00:00:00.000");
263+
assertDateMathEquals("10000", "10000-01-01T00:00:00.000");
264+
assertDateMathEquals("100000", "1970-01-01T00:01:40.000");
265+
265266
// but 10000 with T is still a date format
266267
assertDateMathEquals("10000-01-01T", "10000-01-01T00:00:00.000");
267268
}

0 commit comments

Comments
 (0)