Skip to content

Commit 0c7ba07

Browse files
committed
Ensure date parsing BWC compatibility (#37929)
In order to retain BWC this changes the java date formatters to be able to parse nanoseconds resolution, even if only milliseconds are supported. This used to work on joda time as well so that a user could store a date like `2018-10-03T14:42:44.613469+0000` and then just loose the precision on anything lower than millisecond level.
1 parent 423b3b0 commit 0c7ba07

File tree

2 files changed

+82
-20
lines changed

2 files changed

+82
-20
lines changed

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

+56-20
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public class DateFormatters {
8989
.appendLiteral('T')
9090
.append(STRICT_HOUR_MINUTE_SECOND_FORMATTER)
9191
.optionalStart()
92-
.appendFraction(NANO_OF_SECOND, 3, 3, true)
92+
.appendFraction(NANO_OF_SECOND, 3, 9, true)
9393
.optionalEnd()
9494
.optionalStart()
9595
.appendZoneOrOffsetId()
@@ -158,7 +158,7 @@ public class DateFormatters {
158158
.appendValue(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE)
159159
.appendValue(MINUTE_OF_HOUR, 2, 2, SignStyle.NOT_NEGATIVE)
160160
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
161-
.appendFraction(NANO_OF_SECOND, 1, 3, true)
161+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
162162
.toFormatter(Locale.ROOT);
163163

164164
private static final DateTimeFormatter BASIC_TIME_PRINTER = new DateTimeFormatterBuilder()
@@ -264,7 +264,7 @@ public class DateFormatters {
264264
private static final DateFormatter BASIC_ORDINAL_DATE_TIME = new JavaDateFormatter("basic_ordinal_date_time",
265265
new DateTimeFormatterBuilder().appendPattern("yyyyDDD").append(BASIC_T_TIME_PRINTER)
266266
.appendZoneOrOffsetId().toFormatter(Locale.ROOT),
267-
new DateTimeFormatterBuilder().appendPattern("yyyyDDD").append(BASIC_T_TIME_PRINTER)
267+
new DateTimeFormatterBuilder().appendPattern("yyyyDDD").append(BASIC_T_TIME_FORMATTER)
268268
.appendZoneOrOffsetId().toFormatter(Locale.ROOT),
269269
new DateTimeFormatterBuilder().appendPattern("yyyyDDD").append(BASIC_T_TIME_FORMATTER)
270270
.append(TIME_ZONE_FORMATTER_NO_COLON).toFormatter(Locale.ROOT)
@@ -371,7 +371,7 @@ public class DateFormatters {
371371
.appendValue(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE)
372372
.appendValue(MINUTE_OF_HOUR, 2, 2, SignStyle.NOT_NEGATIVE)
373373
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
374-
.appendFraction(NANO_OF_SECOND, 3, 3, true)
374+
.appendFraction(NANO_OF_SECOND, 3, 9, true)
375375
.appendZoneOrOffsetId()
376376
.toFormatter(Locale.ROOT),
377377
new DateTimeFormatterBuilder()
@@ -380,7 +380,7 @@ public class DateFormatters {
380380
.appendValue(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE)
381381
.appendValue(MINUTE_OF_HOUR, 2, 2, SignStyle.NOT_NEGATIVE)
382382
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
383-
.appendFraction(NANO_OF_SECOND, 3, 3, true)
383+
.appendFraction(NANO_OF_SECOND, 3, 9, true)
384384
.append(TIME_ZONE_FORMATTER_NO_COLON)
385385
.toFormatter(Locale.ROOT)
386386
);
@@ -437,7 +437,7 @@ public class DateFormatters {
437437
.appendLiteral('T')
438438
.append(STRICT_HOUR_MINUTE_SECOND_FORMATTER)
439439
.optionalStart()
440-
.appendFraction(NANO_OF_SECOND, 3, 3, true)
440+
.appendFraction(NANO_OF_SECOND, 3, 9, true)
441441
.optionalEnd()
442442
.toFormatter(Locale.ROOT);
443443

@@ -494,7 +494,7 @@ public class DateFormatters {
494494
// NOTE: this is not a strict formatter to retain the joda time based behaviour, even though it's named like this
495495
private static final DateTimeFormatter STRICT_HOUR_MINUTE_SECOND_MILLIS_FORMATTER = new DateTimeFormatterBuilder()
496496
.append(STRICT_HOUR_MINUTE_SECOND_FORMATTER)
497-
.appendFraction(NANO_OF_SECOND, 1, 3, true)
497+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
498498
.toFormatter(Locale.ROOT);
499499

500500
private static final DateTimeFormatter STRICT_HOUR_MINUTE_SECOND_MILLIS_PRINTER = new DateTimeFormatterBuilder()
@@ -532,12 +532,26 @@ public class DateFormatters {
532532
.append(STRICT_YEAR_MONTH_DAY_FORMATTER)
533533
.appendLiteral("T")
534534
.append(STRICT_HOUR_MINUTE_SECOND_FORMATTER)
535-
// this one here is lenient as well to retain joda time based bwc compatibility
536-
.appendFraction(NANO_OF_SECOND, 1, 3, true)
535+
// this one here is lenient as well to retain joda time based bwc compatibility
536+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
537537
.toFormatter(Locale.ROOT)
538538
);
539539

540-
private static final DateFormatter STRICT_DATE_HOUR_MINUTE_SECOND_MILLIS = STRICT_DATE_HOUR_MINUTE_SECOND_FRACTION;
540+
private static final DateFormatter STRICT_DATE_HOUR_MINUTE_SECOND_MILLIS = new JavaDateFormatter(
541+
"strict_date_hour_minute_second_millis",
542+
new DateTimeFormatterBuilder()
543+
.append(STRICT_YEAR_MONTH_DAY_FORMATTER)
544+
.appendLiteral("T")
545+
.append(STRICT_HOUR_MINUTE_SECOND_MILLIS_PRINTER)
546+
.toFormatter(Locale.ROOT),
547+
new DateTimeFormatterBuilder()
548+
.append(STRICT_YEAR_MONTH_DAY_FORMATTER)
549+
.appendLiteral("T")
550+
.append(STRICT_HOUR_MINUTE_SECOND_FORMATTER)
551+
// this one here is lenient as well to retain joda time based bwc compatibility
552+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
553+
.toFormatter(Locale.ROOT)
554+
);
541555

542556
/*
543557
* Returns a formatter for a two digit hour of day. (HH)
@@ -561,7 +575,7 @@ public class DateFormatters {
561575
.optionalStart()
562576
.appendLiteral(':')
563577
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
564-
.appendFraction(NANO_OF_SECOND, 3, 3, true)
578+
.appendFraction(NANO_OF_SECOND, 3, 9, true)
565579
.optionalEnd()
566580
.toFormatter(Locale.ROOT);
567581

@@ -585,7 +599,7 @@ public class DateFormatters {
585599
.appendValue(MINUTE_OF_HOUR, 2, 2, SignStyle.NOT_NEGATIVE)
586600
.appendLiteral(':')
587601
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
588-
.appendFraction(NANO_OF_SECOND, 1, 3, true)
602+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
589603
.toFormatter(Locale.ROOT);
590604

591605
private static final DateTimeFormatter STRICT_TIME_PRINTER = new DateTimeFormatterBuilder()
@@ -816,7 +830,7 @@ public class DateFormatters {
816830
.appendValue(SECOND_OF_MINUTE, 1, 2, SignStyle.NOT_NEGATIVE)
817831
.optionalEnd()
818832
.optionalStart()
819-
.appendFraction(NANO_OF_SECOND, 1, 3, true)
833+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
820834
.optionalEnd()
821835
.optionalStart().appendZoneOrOffsetId().optionalEnd()
822836
.optionalStart().appendOffset("+HHmm", "Z").optionalEnd()
@@ -840,6 +854,15 @@ public class DateFormatters {
840854
.appendFraction(NANO_OF_SECOND, 1, 3, true)
841855
.toFormatter(Locale.ROOT);
842856

857+
private static final DateTimeFormatter HOUR_MINUTE_SECOND_FRACTION_FORMATTER = new DateTimeFormatterBuilder()
858+
.appendValue(HOUR_OF_DAY, 1, 2, SignStyle.NOT_NEGATIVE)
859+
.appendLiteral(':')
860+
.appendValue(MINUTE_OF_HOUR, 1, 2, SignStyle.NOT_NEGATIVE)
861+
.appendLiteral(':')
862+
.appendValue(SECOND_OF_MINUTE, 1, 2, SignStyle.NOT_NEGATIVE)
863+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
864+
.toFormatter(Locale.ROOT);
865+
843866
private static final DateTimeFormatter ORDINAL_DATE_FORMATTER = new DateTimeFormatterBuilder()
844867
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
845868
.appendLiteral('-')
@@ -872,7 +895,7 @@ public class DateFormatters {
872895

873896
private static final DateTimeFormatter TIME_PREFIX = new DateTimeFormatterBuilder()
874897
.append(TIME_NO_MILLIS_FORMATTER)
875-
.appendFraction(NANO_OF_SECOND, 1, 3, true)
898+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
876899
.toFormatter(Locale.ROOT);
877900

878901
private static final DateTimeFormatter WEEK_DATE_FORMATTER = new DateTimeFormatterBuilder()
@@ -910,8 +933,7 @@ public class DateFormatters {
910933
/*
911934
* Returns a formatter that combines a full date, two digit hour of day,
912935
* two digit minute of hour, two digit second of minute, and three digit
913-
* fraction of second (yyyy-MM-dd'T'HH:mm:ss.SSS). Parsing will parse up
914-
* to 3 fractional second digits.
936+
* fraction of second (yyyy-MM-dd'T'HH:mm:ss.SSS).
915937
*/
916938
private static final DateFormatter DATE_HOUR_MINUTE_SECOND_MILLIS =
917939
new JavaDateFormatter("date_hour_minute_second_millis",
@@ -926,7 +948,18 @@ public class DateFormatters {
926948
.append(HOUR_MINUTE_SECOND_MILLIS_FORMATTER)
927949
.toFormatter(Locale.ROOT));
928950

929-
private static final DateFormatter DATE_HOUR_MINUTE_SECOND_FRACTION = DATE_HOUR_MINUTE_SECOND_MILLIS;
951+
private static final DateFormatter DATE_HOUR_MINUTE_SECOND_FRACTION =
952+
new JavaDateFormatter("date_hour_minute_second_fraction",
953+
new DateTimeFormatterBuilder()
954+
.append(STRICT_YEAR_MONTH_DAY_FORMATTER)
955+
.appendLiteral("T")
956+
.append(STRICT_HOUR_MINUTE_SECOND_MILLIS_PRINTER)
957+
.toFormatter(Locale.ROOT),
958+
new DateTimeFormatterBuilder()
959+
.append(DATE_FORMATTER)
960+
.appendLiteral("T")
961+
.append(HOUR_MINUTE_SECOND_FRACTION_FORMATTER)
962+
.toFormatter(Locale.ROOT));
930963

931964
/*
932965
* Returns a formatter that combines a full date, two digit hour of day,
@@ -960,7 +993,7 @@ public class DateFormatters {
960993
.optionalStart()
961994
.appendLiteral(':')
962995
.appendValue(SECOND_OF_MINUTE, 1, 2, SignStyle.NOT_NEGATIVE)
963-
.appendFraction(NANO_OF_SECOND, 1, 3, true)
996+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
964997
.optionalEnd()
965998
.toFormatter(Locale.ROOT);
966999

@@ -1031,6 +1064,9 @@ public class DateFormatters {
10311064
private static final DateFormatter HOUR_MINUTE_SECOND_MILLIS = new JavaDateFormatter("hour_minute_second_millis",
10321065
STRICT_HOUR_MINUTE_SECOND_MILLIS_PRINTER, HOUR_MINUTE_SECOND_MILLIS_FORMATTER);
10331066

1067+
private static final DateFormatter HOUR_MINUTE_SECOND_FRACTION = new JavaDateFormatter("hour_minute_second_fraction",
1068+
STRICT_HOUR_MINUTE_SECOND_MILLIS_PRINTER, HOUR_MINUTE_SECOND_FRACTION_FORMATTER);
1069+
10341070
/*
10351071
* Returns a formatter for a two digit hour of day and two digit minute of
10361072
* hour. (HH:mm)
@@ -1065,7 +1101,7 @@ public class DateFormatters {
10651101
.optionalStart()
10661102
.appendLiteral(':')
10671103
.appendValue(SECOND_OF_MINUTE, 1, 2, SignStyle.NOT_NEGATIVE)
1068-
.appendFraction(NANO_OF_SECOND, 1, 3, true)
1104+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
10691105
.optionalEnd()
10701106
.toFormatter(Locale.ROOT);
10711107

@@ -1329,7 +1365,7 @@ public static DateFormatter forPattern(String input) {
13291365
} else if ("hourMinuteSecond".equals(input) || "hour_minute_second".equals(input)) {
13301366
return HOUR_MINUTE_SECOND;
13311367
} else if ("hourMinuteSecondFraction".equals(input) || "hour_minute_second_fraction".equals(input)) {
1332-
return HOUR_MINUTE_SECOND_MILLIS;
1368+
return HOUR_MINUTE_SECOND_FRACTION;
13331369
} else if ("hourMinuteSecondMillis".equals(input) || "hour_minute_second_millis".equals(input)) {
13341370
return HOUR_MINUTE_SECOND_MILLIS;
13351371
} else if ("ordinalDate".equals(input) || "ordinal_date".equals(input)) {

0 commit comments

Comments
 (0)