Kaynağa Gözat

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.
David Roberts 6 yıl önce
ebeveyn
işleme
cce1a889bf

+ 3 - 3
server/src/main/java/org/elasticsearch/common/time/DateFormatters.java

@@ -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));
 
     /////////////////////////////////////////

+ 7 - 0
server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java

@@ -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() {

+ 52 - 0
server/src/test/java/org/elasticsearch/common/time/DateFormattersTests.java

@@ -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