[7.x] Enable ResolverStyle.STRICT for java formatters backport(#46675) (#47913)

Joda was using ResolverStyle.STRICT when parsing. This means that date will be validated to be a correct year, year-of-month, day-of-month
However, we also want to make it works with Year-Of-Era as Joda used to, hence custom temporalquery.localdate in DateFormatters.from
Within DateFormatters we use the correct uuuu year instead of yyyy year of era

worth noting: if yyyy(without an era) is used in code, the parsing result will be a TemporalAccessor which will fail to be converted into LocalDate. We mostly use DateFormatters.from so this takes care of this. If possible the uuuu format should be used.
This commit is contained in:
Przemyslaw Gomulka 2019-10-11 21:19:56 +02:00 committed by GitHub
parent 627faf1850
commit 6ab58de7ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 562 additions and 314 deletions

View File

@ -98,9 +98,9 @@ enum DateFormat {
final DateFormatter formatter = dateFormatter;
return text -> {
TemporalAccessor accessor = formatter.parse(text);
// if there is no year, we fall back to the current one and
// if there is no year nor year-of-era, we fall back to the current one and
// fill the rest of the date up with the parsed date
if (accessor.isSupported(ChronoField.YEAR) == false) {
if (accessor.isSupported(ChronoField.YEAR) == false && accessor.isSupported(ChronoField.YEAR_OF_ERA) == false ) {
int year = LocalDate.now(ZoneOffset.UTC).getYear();
ZonedDateTime newTime = Instant.EPOCH.atZone(ZoneOffset.UTC).withYear(year);
for (ChronoField field : FIELDS) {

View File

@ -44,7 +44,7 @@ public class DateFormatTests extends ESTestCase {
equalTo("11 24 01:29:01"));
}
public void testParseJavaWithTimeZone() {
public void testParseYearOfEraJavaWithTimeZone() {
Function<String, ZonedDateTime> javaFunction = DateFormat.Java.getFunction("yyyy-MM-dd'T'HH:mm:ss.SSSZZ",
ZoneOffset.UTC, Locale.ROOT);
ZonedDateTime datetime = javaFunction.apply("2018-02-05T13:44:56.657+0100");
@ -52,6 +52,14 @@ public class DateFormatTests extends ESTestCase {
assertThat(expectedDateTime, is("2018-02-05T12:44:56.657Z"));
}
public void testParseYearJavaWithTimeZone() {
Function<String, ZonedDateTime> javaFunction = DateFormat.Java.getFunction("uuuu-MM-dd'T'HH:mm:ss.SSSZZ",
ZoneOffset.UTC, Locale.ROOT);
ZonedDateTime datetime = javaFunction.apply("2018-02-05T13:44:56.657+0100");
String expectedDateTime = DateFormatter.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withZone(ZoneOffset.UTC).format(datetime);
assertThat(expectedDateTime, is("2018-02-05T12:44:56.657Z"));
}
public void testParseJavaDefaultYear() {
String format = randomFrom("8dd/MM", "dd/MM");
ZoneId timezone = DateUtils.of("Europe/Amsterdam");

View File

@ -872,6 +872,10 @@ public class JavaJodaTimeDuellingTests extends ESTestCase {
assertSameDate("2018-10-10T10:11:12,123+05:30", format, jodaFormatter, javaFormatter);
}
public void testParsingLocalDateFromYearOfEra(){
//with strict resolving, YearOfEra expect an era, otherwise it won't resolve to a date
assertSameDate("2018363","yyyyDDD",Joda.forPattern("YYYYDDD"),DateFormatter.forPattern("uuuuDDD"));
}
public void testParsingMissingTimezone() {
long millisJava = DateFormatter.forPattern("8yyyy-MM-dd HH:mm:ss").parseMillis("2018-02-18 17:47:17");
long millisJoda = DateFormatter.forPattern("yyyy-MM-dd HH:mm:ss").parseMillis("2018-02-18 17:47:17");

View File

@ -198,7 +198,7 @@ public class DateDerivativeIT extends ESIntegTestCase {
List<IndexRequestBuilder> builders = new ArrayList<>();
ZoneId timezone = ZoneId.of("CET");
DateFormatter formatter = DateFormatter.forPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(timezone);
DateFormatter formatter = DateFormatter.forPattern("uuuu-MM-dd'T'HH:mm:ss").withZone(timezone);
// epoch millis: 1332547200000
addNTimes(1, IDX_DST_START, DateFormatters.from(formatter.parse("2012-03-24T01:00:00")), builders);
// day with dst shift, only 23h long
@ -223,7 +223,7 @@ public class DateDerivativeIT extends ESIntegTestCase {
List<? extends Bucket> buckets = deriv.getBuckets();
assertThat(buckets.size(), equalTo(4));
DateFormatter dateFormatter = DateFormatter.forPattern("yyyy-MM-dd");
DateFormatter dateFormatter = DateFormatter.forPattern("uuuu-MM-dd");
ZonedDateTime expectedKeyFirstBucket =
LocalDate.from(dateFormatter.parse("2012-03-24")).atStartOfDay(timezone).withZoneSameInstant(ZoneOffset.UTC);
assertBucket(buckets.get(0), expectedKeyFirstBucket, 1L, nullValue(), null, null);
@ -250,7 +250,7 @@ public class DateDerivativeIT extends ESIntegTestCase {
ZoneId timezone = ZoneId.of("CET");
List<IndexRequestBuilder> builders = new ArrayList<>();
DateFormatter formatter = DateFormatter.forPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(timezone);
DateFormatter formatter = DateFormatter.forPattern("uuuu-MM-dd'T'HH:mm:ss").withZone(timezone);
addNTimes(1, IDX_DST_END, DateFormatters.from(formatter.parse("2012-10-27T01:00:00")), builders);
// day with dst shift -1h, 25h long
addNTimes(2, IDX_DST_END, DateFormatters.from(formatter.parse("2012-10-28T01:00:00")), builders);
@ -274,7 +274,7 @@ public class DateDerivativeIT extends ESIntegTestCase {
List<? extends Bucket> buckets = deriv.getBuckets();
assertThat(buckets.size(), equalTo(4));
DateFormatter dateFormatter = DateFormatter.forPattern("yyyy-MM-dd").withZone(ZoneOffset.UTC);
DateFormatter dateFormatter = DateFormatter.forPattern("uuuu-MM-dd").withZone(ZoneOffset.UTC);
ZonedDateTime expectedKeyFirstBucket =
LocalDate.from(dateFormatter.parse("2012-10-27")).atStartOfDay(timezone).withZoneSameInstant(ZoneOffset.UTC);
@ -303,7 +303,7 @@ public class DateDerivativeIT extends ESIntegTestCase {
ZoneId timezone = ZoneId.of("Asia/Kathmandu");
List<IndexRequestBuilder> builders = new ArrayList<>();
DateFormatter formatter = DateFormatter.forPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(timezone);
DateFormatter formatter = DateFormatter.forPattern("uuuu-MM-dd'T'HH:mm:ss").withZone(timezone);
addNTimes(1, IDX_DST_KATHMANDU, DateFormatters.from(formatter.parse("1985-12-31T22:30:00")), builders);
// the shift happens during the next bucket, which includes the 45min that do not start on the full hour
addNTimes(2, IDX_DST_KATHMANDU, DateFormatters.from(formatter.parse("1985-12-31T23:30:00")), builders);
@ -327,7 +327,7 @@ public class DateDerivativeIT extends ESIntegTestCase {
List<? extends Bucket> buckets = deriv.getBuckets();
assertThat(buckets.size(), equalTo(4));
DateFormatter dateFormatter = DateFormatter.forPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(ZoneOffset.UTC);
DateFormatter dateFormatter = DateFormatter.forPattern("uuuu-MM-dd'T'HH:mm:ss").withZone(ZoneOffset.UTC);
ZonedDateTime expectedKeyFirstBucket =
LocalDateTime.from(dateFormatter.parse("1985-12-31T22:00:00")).atZone(timezone).withZoneSameInstant(ZoneOffset.UTC);

View File

@ -17,7 +17,7 @@ import static org.elasticsearch.xpack.core.ilm.LifecycleSettings.LIFECYCLE_PARSE
public class IndexLifecycleOriginationDateParser {
private static final DateFormatter DATE_FORMATTER = DateFormatter.forPattern("yyyy.MM.dd");
private static final DateFormatter DATE_FORMATTER = DateFormatter.forPattern("uuuu.MM.dd");
private static final String INDEX_NAME_REGEX = "^.*-(\\d{4}.\\d{2}.\\d{2})(-[\\d]+)?$";
private static final Pattern INDEX_NAME_PATTERN = Pattern.compile(INDEX_NAME_REGEX);

View File

@ -17,7 +17,7 @@ import static org.hamcrest.Matchers.is;
public class IndexLifecycleOriginationDateParserTests extends ESTestCase {
private static final DateFormatter dateFormatter = DateFormatter.forPattern("yyyy.MM.dd");
private static final DateFormatter dateFormatter = DateFormatter.forPattern("uuuu.MM.dd");
public void testShouldParseIndexNameReturnsFalseWhenOriginationDateIsSet() {
Settings settings = Settings.builder()