Make ISO8601 date parser accept timezone when time does not have seconds (#41896)

Prior to this change the ISO8601 date parser would only
parse an optional timezone if seconds were specified.
This change moves the timezone to the same level of
optional components as hour, so that timestamps without
minutes or seconds may optionally contain a timezone.
It also adds a unit test to cover all the supported
formats.
This commit is contained in:
David Roberts 2019-05-08 13:46:58 +01:00
parent 957046dad0
commit 452ee55cdb
3 changed files with 62 additions and 3 deletions

View File

@ -178,7 +178,7 @@ public class DateFormatters {
/**
* Returns a ISO 8601 compatible date time formatter and parser.
* This is not fully compatible to the existing spec, which would require far more edge cases, but merely compatible with the
* existing joda time ISO data formater
* existing joda time ISO date formatter
*/
private static final DateFormatter ISO_8601 = new JavaDateFormatter("iso8601", STRICT_DATE_OPTIONAL_TIME_PRINTER,
new DateTimeFormatterBuilder()
@ -201,6 +201,8 @@ public class DateFormatters {
.appendFraction(NANO_OF_SECOND, 1, 9, false)
.optionalEnd()
.optionalEnd()
.optionalEnd()
.optionalEnd()
.optionalStart()
.appendZoneOrOffsetId()
.optionalEnd()
@ -208,8 +210,6 @@ public class DateFormatters {
.append(TIME_ZONE_FORMATTER_NO_COLON)
.optionalEnd()
.optionalEnd()
.optionalEnd()
.optionalEnd()
.toFormatter(Locale.ROOT));
/////////////////////////////////////////

View File

@ -733,14 +733,21 @@ public class JavaJodaTimeDuellingTests extends ESTestCase {
JodaDateFormatter jodaFormatter = new JodaDateFormatter(format, isoFormatter, isoFormatter);
DateFormatter javaFormatter = DateFormatter.forPattern(format);
assertSameDate("2018-10-10", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10+0430", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11-08:00", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11Z", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11:12", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11:12+0100", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11:12.123", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11:12.123Z", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11:12.123+0000", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11:12,123", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11:12,123Z", format, jodaFormatter, javaFormatter);
assertSameDate("2018-10-10T10:11:12,123+05:30", format, jodaFormatter, javaFormatter);
}
public void testParsingMissingTimezone() {

View File

@ -198,6 +198,58 @@ public class DateFormattersTests extends ESTestCase {
formatter.format(formatter.parse("2018-05-15T17:14:56.123456789+01:00"));
}
public void testIso8601Parsing() {
DateFormatter formatter = DateFormatters.forPattern("iso8601");
// timezone not allowed with just date
formatter.format(formatter.parse("2018-05-15"));
formatter.format(formatter.parse("2018-05-15T17"));
formatter.format(formatter.parse("2018-05-15T17Z"));
formatter.format(formatter.parse("2018-05-15T17+0100"));
formatter.format(formatter.parse("2018-05-15T17+01:00"));
formatter.format(formatter.parse("2018-05-15T17:14"));
formatter.format(formatter.parse("2018-05-15T17:14Z"));
formatter.format(formatter.parse("2018-05-15T17:14-0100"));
formatter.format(formatter.parse("2018-05-15T17:14-01:00"));
formatter.format(formatter.parse("2018-05-15T17:14:56"));
formatter.format(formatter.parse("2018-05-15T17:14:56Z"));
formatter.format(formatter.parse("2018-05-15T17:14:56+0100"));
formatter.format(formatter.parse("2018-05-15T17:14:56+01:00"));
// milliseconds can be separated using comma or decimal point
formatter.format(formatter.parse("2018-05-15T17:14:56.123"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123Z"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123-0100"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123-01:00"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123Z"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123+0100"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123+01:00"));
// microseconds can be separated using comma or decimal point
formatter.format(formatter.parse("2018-05-15T17:14:56.123456"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123456Z"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123456+0100"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123456+01:00"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123456"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123456Z"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123456-0100"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123456-01:00"));
// nanoseconds can be separated using comma or decimal point
formatter.format(formatter.parse("2018-05-15T17:14:56.123456789"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123456789Z"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123456789-0100"));
formatter.format(formatter.parse("2018-05-15T17:14:56.123456789-01:00"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123456789"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123456789Z"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123456789+0100"));
formatter.format(formatter.parse("2018-05-15T17:14:56,123456789+01:00"));
}
public void testRoundupFormatterWithEpochDates() {
assertRoundupFormatter("epoch_millis", "1234567890", 1234567890L);
// also check nanos of the epoch_millis formatter if it is rounded up to the nano second