Skip to content

Commit e95b0c4

Browse files
authored
Allow parsing timezone without fully provided time backport(#50178) (#50740)
strict_date_optional_time changes to have optional minute part. It already allowed optional second and fraction of second part. This allows parsing 2018-01-01T00+01 , 2018-01-01T00:00+01 , 2018-01-01T00:00:00+01 , 2018-01-01T00:00:00.000+01 It won't allow parsing a timezone without an hour part as this is not allowed by iso8601 spec closes #49351
1 parent 9d1567b commit e95b0c4

File tree

2 files changed

+86
-28
lines changed

2 files changed

+86
-28
lines changed

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

+25-25
Original file line numberDiff line numberDiff line change
@@ -108,31 +108,31 @@ public class DateFormatters {
108108
private static final DateTimeFormatter STRICT_DATE_OPTIONAL_TIME_FORMATTER = new DateTimeFormatterBuilder()
109109
.append(STRICT_YEAR_MONTH_DAY_FORMATTER)
110110
.optionalStart()
111-
.appendLiteral('T')
112-
.optionalStart()
113-
.appendValue(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE)
114-
.optionalStart()
115-
.appendLiteral(':')
116-
.appendValue(MINUTE_OF_HOUR, 2, 2, SignStyle.NOT_NEGATIVE)
117-
.optionalStart()
118-
.appendLiteral(':')
119-
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
120-
.optionalStart()
121-
.appendFraction(NANO_OF_SECOND, 1, 9, true)
122-
.optionalEnd()
123-
.optionalStart()
124-
.appendLiteral(',')
125-
.appendFraction(NANO_OF_SECOND, 1, 9, false)
126-
.optionalEnd()
127-
.optionalEnd()
128-
.optionalStart()
129-
.appendZoneOrOffsetId()
130-
.optionalEnd()
131-
.optionalStart()
132-
.append(TIME_ZONE_FORMATTER_NO_COLON)
133-
.optionalEnd()
134-
.optionalEnd()
135-
.optionalEnd()
111+
.appendLiteral('T')
112+
.optionalStart()
113+
.appendValue(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE)
114+
.optionalStart()
115+
.appendLiteral(':')
116+
.appendValue(MINUTE_OF_HOUR, 2, 2, SignStyle.NOT_NEGATIVE)
117+
.optionalStart()
118+
.appendLiteral(':')
119+
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
120+
.optionalStart()
121+
.appendFraction(NANO_OF_SECOND, 1, 9, true)
122+
.optionalEnd()
123+
.optionalStart()
124+
.appendLiteral(',')
125+
.appendFraction(NANO_OF_SECOND, 1, 9, false)
126+
.optionalEnd()
127+
.optionalEnd()
128+
.optionalEnd()
129+
.optionalStart()
130+
.appendZoneOrOffsetId()
131+
.optionalEnd()
132+
.optionalStart()
133+
.append(TIME_ZONE_FORMATTER_NO_COLON)
134+
.optionalEnd()
135+
.optionalEnd()
136136
.optionalEnd()
137137
.toFormatter(Locale.ROOT)
138138
.withResolverStyle(ResolverStyle.STRICT);

server/src/test/java/org/elasticsearch/common/joda/JavaJodaTimeDuellingTests.java

+61-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,42 @@ public class JavaJodaTimeDuellingTests extends ESTestCase {
4646
protected boolean enableWarningsCheck() {
4747
return false;
4848
}
49+
50+
public void testTimezoneParsing() {
51+
/** this testcase won't work in joda. See comment in {@link #testPartialTimeParsing()}
52+
* assertSameDateAs("2016-11-30T+01", "strict_date_optional_time", "strict_date_optional_time");
53+
*/
54+
assertSameDateAs("2016-11-30T00+01", "strict_date_optional_time", "strict_date_optional_time");
55+
assertSameDateAs("2016-11-30T00+0100", "strict_date_optional_time", "strict_date_optional_time");
56+
assertSameDateAs("2016-11-30T00+01:00", "strict_date_optional_time", "strict_date_optional_time");
57+
}
58+
59+
public void testPartialTimeParsing() {
60+
/*
61+
This does not work in Joda as it reports 2016-11-30T01:00:00Z
62+
because StrictDateOptionalTime confuses +01 with an hour (which is a signed fixed length digit)
63+
assertSameDateAs("2016-11-30T+01", "strict_date_optional_time", "strict_date_optional_time");
64+
ES java.time implementation does not suffer from this,
65+
but we intentionally not allow parsing timezone without an time part as it is not allowed in iso8601
66+
*/
67+
assertJavaTimeParseException("2016-11-30T+01","strict_date_optional_time");
68+
69+
assertSameDateAs("2016-11-30T12+01", "strict_date_optional_time", "strict_date_optional_time");
70+
assertSameDateAs("2016-11-30T12:00+01", "strict_date_optional_time", "strict_date_optional_time");
71+
assertSameDateAs("2016-11-30T12:00:00+01", "strict_date_optional_time", "strict_date_optional_time");
72+
assertSameDateAs("2016-11-30T12:00:00.000+01", "strict_date_optional_time", "strict_date_optional_time");
73+
74+
//without timezone
75+
assertSameDateAs("2016-11-30T", "strict_date_optional_time", "strict_date_optional_time");
76+
assertSameDateAs("2016-11-30T12", "strict_date_optional_time", "strict_date_optional_time");
77+
assertSameDateAs("2016-11-30T12:00", "strict_date_optional_time", "strict_date_optional_time");
78+
assertSameDateAs("2016-11-30T12:00:00", "strict_date_optional_time", "strict_date_optional_time");
79+
assertSameDateAs("2016-11-30T12:00:00.000", "strict_date_optional_time", "strict_date_optional_time");
80+
}
81+
4982
// date_optional part of a parser names "strict_date_optional_time" or "date_optional"time
5083
// means that date part can be partially parsed.
51-
public void testPartialParsing() {
84+
public void testPartialDateParsing() {
5285
assertSameDateAs("2001", "strict_date_optional_time_nanos", "strict_date_optional_time");
5386
assertSameDateAs("2001-01", "strict_date_optional_time_nanos", "strict_date_optional_time");
5487
assertSameDateAs("2001-01-01", "strict_date_optional_time_nanos", "strict_date_optional_time");
@@ -883,9 +916,28 @@ public void testParsingMissingTimezone() {
883916
}
884917

885918
private void assertSamePrinterOutput(String format, ZonedDateTime javaDate, DateTime jodaDate) {
919+
DateFormatter dateFormatter = DateFormatter.forPattern(format);
920+
JodaDateFormatter jodaDateFormatter = Joda.forPattern(format);
921+
922+
assertSamePrinterOutput(format, javaDate, jodaDate, dateFormatter, jodaDateFormatter);
923+
}
924+
925+
private void assertSamePrinterOutput(String format, ZonedDateTime javaDate, DateTime jodaDate, Locale locale) {
926+
DateFormatter dateFormatter = DateFormatter.forPattern(format).withLocale(locale);
927+
DateFormatter jodaDateFormatter = Joda.forPattern(format).withLocale(locale);
928+
929+
assertSamePrinterOutput(format, javaDate, jodaDate, dateFormatter, jodaDateFormatter);
930+
}
931+
932+
private void assertSamePrinterOutput(String format,
933+
ZonedDateTime javaDate,
934+
DateTime jodaDate,
935+
DateFormatter dateFormatter,
936+
DateFormatter jodaDateFormatter) {
937+
String javaTimeOut = dateFormatter.format(javaDate);
938+
String jodaTimeOut = jodaDateFormatter.formatJoda(jodaDate);
939+
886940
assertThat(jodaDate.getMillis(), is(javaDate.toInstant().toEpochMilli()));
887-
String javaTimeOut = DateFormatter.forPattern(format).format(javaDate);
888-
String jodaTimeOut = Joda.forPattern(format).formatJoda(jodaDate);
889941

890942
if (JavaVersion.current().getVersion().get(0) == 8 && javaTimeOut.endsWith(".0")
891943
&& (format.equals("epoch_second") || format.equals("epoch_millis"))) {
@@ -904,6 +956,12 @@ private void assertSameDate(String input, String format) {
904956
assertSameDate(input, format, jodaFormatter, javaFormatter);
905957
}
906958

959+
private void assertSameDate(String input, String format, Locale locale) {
960+
DateFormatter jodaFormatter = Joda.forPattern(format).withLocale(locale);
961+
DateFormatter javaFormatter = DateFormatter.forPattern(format).withLocale(locale);
962+
assertSameDate(input, format, jodaFormatter, javaFormatter);
963+
}
964+
907965
private void assertSameDate(String input, String format, DateFormatter jodaFormatter, DateFormatter javaFormatter) {
908966
DateTime jodaDateTime = jodaFormatter.parseJoda(input);
909967

0 commit comments

Comments
 (0)