Round up parsers should be based on a list of parsers backport(#62290) (#62604)

a dateformatter can be created with a list of parsers which are iterated
during parsing and the first one that passes will return a parsed date.
DateMathParser should do the same, when created based on a list of
non-rounding parsers it should also iterate over all of them - it is at
the moment only taking first element

closing #62207
This commit is contained in:
Przemyslaw Gomulka 2020-09-18 12:03:20 +02:00 committed by GitHub
parent 6e071580ff
commit d87268a264
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 5 deletions

View File

@ -105,18 +105,30 @@ class JavaDateFormatter implements DateFormatter {
} else { } else {
this.parsers = Arrays.asList(parsers); this.parsers = Arrays.asList(parsers);
} }
//this is when the RoundUp Formatter is created. In further merges (with ||) it will only append this one to a list.
List<DateTimeFormatter> roundUp = createRoundUpParser(format, roundupParserConsumer); List<DateTimeFormatter> roundUp = createRoundUpParser(format, roundupParserConsumer);
this.roundupParser = new RoundUpFormatter(format, roundUp) ; this.roundupParser = new RoundUpFormatter(format, roundUp) ;
} }
/**
* This is when the RoundUp Formatters are created. In further merges (with ||) it will only append them to a list.
* || is not expected to be provided as format when a RoundUp formatter is created. It will be splitted before in
* <code>DateFormatter.forPattern</code>
* JavaDateFormatter created with a custom format like <code>DateFormatter.forPattern("YYYY")</code> will only have one parser
* It is however possible to have a JavaDateFormatter with multiple parsers. For instance see a "date_time" formatter in
* <code>DateFormatters</code>.
* This means that we need to also have multiple RoundUp parsers.
*/
private List<DateTimeFormatter> createRoundUpParser(String format, private List<DateTimeFormatter> createRoundUpParser(String format,
Consumer<DateTimeFormatterBuilder> roundupParserConsumer) { Consumer<DateTimeFormatterBuilder> roundupParserConsumer) {
if (format.contains("||") == false) { if (format.contains("||") == false) {
List<DateTimeFormatter> roundUpParsers = new ArrayList<>();
for (DateTimeFormatter parser : this.parsers) {
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(); DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.append(this.parsers.get(0)); builder.append(parser);
roundupParserConsumer.accept(builder); roundupParserConsumer.accept(builder);
return Arrays.asList(builder.toFormatter(locale())); roundUpParsers.add(builder.toFormatter(locale()));
}
return roundUpParsers;
} }
return null; return null;
} }

View File

@ -27,10 +27,14 @@ import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.LongSupplier; import java.util.function.LongSupplier;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
public class JavaDateMathParserTests extends ESTestCase { public class JavaDateMathParserTests extends ESTestCase {
@ -38,6 +42,47 @@ public class JavaDateMathParserTests extends ESTestCase {
private final DateFormatter formatter = DateFormatter.forPattern("date_optional_time||epoch_millis"); private final DateFormatter formatter = DateFormatter.forPattern("date_optional_time||epoch_millis");
private final DateMathParser parser = formatter.toDateMathParser(); private final DateMathParser parser = formatter.toDateMathParser();
public void testRoundUpParserBasedOnList() {
DateFormatter formatter = new JavaDateFormatter("test", new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd")
.toFormatter(Locale.ROOT),
new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd'T'HH:mm:ss.S").appendZoneOrOffsetId().toFormatter(Locale.ROOT)
.withResolverStyle(ResolverStyle.STRICT),
new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd'T'HH:mm:ss.S").appendOffset("+HHmm", "Z").toFormatter(Locale.ROOT)
.withResolverStyle(ResolverStyle.STRICT));
Instant parsed = formatter.toDateMathParser().parse("1970-01-01T00:00:00.0+0000", () -> 0L, true, (ZoneId) null);
assertThat(parsed.toEpochMilli(), equalTo(0L));
}
public void testMergingOfMultipleParsers() {
//date_time has 2 parsers, date_time_no_millis has 4. Parsing with rounding should be able to use all of them
DateFormatter formatter = DateFormatter.forPattern("date_time||date_time_no_millis");
//date_time 2 parsers
Instant parsed = formatter.toDateMathParser().parse("1970-01-01T00:00:00.0+00:00", () -> 0L, true, (ZoneId) null);
assertThat(parsed.toEpochMilli(), equalTo(0L));
parsed = formatter.toDateMathParser().parse("1970-01-01T00:00:00.0+0000", () -> 0L, true, (ZoneId) null);
assertThat(parsed.toEpochMilli(), equalTo(0L));
//date_time_no_millis 4 parsers
parsed = formatter.toDateMathParser().parse("1970-01-01T00:00:00+00:00", () -> 0L, true, (ZoneId) null);
assertThat(parsed.toEpochMilli(), equalTo(999L));//defaulting millis
parsed = formatter.toDateMathParser().parse("1970-01-01T00:00:00+0000", () -> 0L, true, (ZoneId) null);
assertThat(parsed.toEpochMilli(), equalTo(999L));//defaulting millis
parsed = formatter.toDateMathParser().parse("1970-01-01T00:00:00UTC+00:00", () -> 0L, true, (ZoneId) null);
assertThat(parsed.toEpochMilli(), equalTo(999L));//defaulting millis
// this one is actually still using parser number 3. I don't see a combination to use parser number 4
parsed = formatter.toDateMathParser().parse("1970-01-01T00:00:00", () -> 0L, true, (ZoneId) null);
assertThat(parsed.toEpochMilli(), equalTo(999L));//defaulting millis
}
public void testOverridingLocaleOrZoneAndCompositeRoundUpParser() { public void testOverridingLocaleOrZoneAndCompositeRoundUpParser() {
//the pattern has to be composite and the match should not be on the first one //the pattern has to be composite and the match should not be on the first one
DateFormatter formatter = DateFormatter.forPattern("date||epoch_millis").withLocale(randomLocale(random())); DateFormatter formatter = DateFormatter.forPattern("date||epoch_millis").withLocale(randomLocale(random()));