Skip to content

Commit

Permalink
Allow parsing timezone without fully provided time backport(#50178) (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
pgomulka committed Jan 8, 2020
1 parent 9d1567b commit e95b0c4
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,31 +108,31 @@ public class DateFormatters {
private static final DateTimeFormatter STRICT_DATE_OPTIONAL_TIME_FORMATTER = new DateTimeFormatterBuilder()
.append(STRICT_YEAR_MONTH_DAY_FORMATTER)
.optionalStart()
.appendLiteral('T')
.optionalStart()
.appendValue(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE)
.optionalStart()
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2, 2, SignStyle.NOT_NEGATIVE)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
.optionalStart()
.appendFraction(NANO_OF_SECOND, 1, 9, true)
.optionalEnd()
.optionalStart()
.appendLiteral(',')
.appendFraction(NANO_OF_SECOND, 1, 9, false)
.optionalEnd()
.optionalEnd()
.optionalStart()
.appendZoneOrOffsetId()
.optionalEnd()
.optionalStart()
.append(TIME_ZONE_FORMATTER_NO_COLON)
.optionalEnd()
.optionalEnd()
.optionalEnd()
.appendLiteral('T')
.optionalStart()
.appendValue(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE)
.optionalStart()
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2, 2, SignStyle.NOT_NEGATIVE)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2, 2, SignStyle.NOT_NEGATIVE)
.optionalStart()
.appendFraction(NANO_OF_SECOND, 1, 9, true)
.optionalEnd()
.optionalStart()
.appendLiteral(',')
.appendFraction(NANO_OF_SECOND, 1, 9, false)
.optionalEnd()
.optionalEnd()
.optionalEnd()
.optionalStart()
.appendZoneOrOffsetId()
.optionalEnd()
.optionalStart()
.append(TIME_ZONE_FORMATTER_NO_COLON)
.optionalEnd()
.optionalEnd()
.optionalEnd()
.toFormatter(Locale.ROOT)
.withResolverStyle(ResolverStyle.STRICT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,42 @@ public class JavaJodaTimeDuellingTests extends ESTestCase {
protected boolean enableWarningsCheck() {
return false;
}

public void testTimezoneParsing() {
/** this testcase won't work in joda. See comment in {@link #testPartialTimeParsing()}
* assertSameDateAs("2016-11-30T+01", "strict_date_optional_time", "strict_date_optional_time");
*/
assertSameDateAs("2016-11-30T00+01", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T00+0100", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T00+01:00", "strict_date_optional_time", "strict_date_optional_time");
}

public void testPartialTimeParsing() {
/*
This does not work in Joda as it reports 2016-11-30T01:00:00Z
because StrictDateOptionalTime confuses +01 with an hour (which is a signed fixed length digit)
assertSameDateAs("2016-11-30T+01", "strict_date_optional_time", "strict_date_optional_time");
ES java.time implementation does not suffer from this,
but we intentionally not allow parsing timezone without an time part as it is not allowed in iso8601
*/
assertJavaTimeParseException("2016-11-30T+01","strict_date_optional_time");

assertSameDateAs("2016-11-30T12+01", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T12:00+01", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T12:00:00+01", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T12:00:00.000+01", "strict_date_optional_time", "strict_date_optional_time");

//without timezone
assertSameDateAs("2016-11-30T", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T12", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T12:00", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T12:00:00", "strict_date_optional_time", "strict_date_optional_time");
assertSameDateAs("2016-11-30T12:00:00.000", "strict_date_optional_time", "strict_date_optional_time");
}

// date_optional part of a parser names "strict_date_optional_time" or "date_optional"time
// means that date part can be partially parsed.
public void testPartialParsing() {
public void testPartialDateParsing() {
assertSameDateAs("2001", "strict_date_optional_time_nanos", "strict_date_optional_time");
assertSameDateAs("2001-01", "strict_date_optional_time_nanos", "strict_date_optional_time");
assertSameDateAs("2001-01-01", "strict_date_optional_time_nanos", "strict_date_optional_time");
Expand Down Expand Up @@ -883,9 +916,28 @@ public void testParsingMissingTimezone() {
}

private void assertSamePrinterOutput(String format, ZonedDateTime javaDate, DateTime jodaDate) {
DateFormatter dateFormatter = DateFormatter.forPattern(format);
JodaDateFormatter jodaDateFormatter = Joda.forPattern(format);

assertSamePrinterOutput(format, javaDate, jodaDate, dateFormatter, jodaDateFormatter);
}

private void assertSamePrinterOutput(String format, ZonedDateTime javaDate, DateTime jodaDate, Locale locale) {
DateFormatter dateFormatter = DateFormatter.forPattern(format).withLocale(locale);
DateFormatter jodaDateFormatter = Joda.forPattern(format).withLocale(locale);

assertSamePrinterOutput(format, javaDate, jodaDate, dateFormatter, jodaDateFormatter);
}

private void assertSamePrinterOutput(String format,
ZonedDateTime javaDate,
DateTime jodaDate,
DateFormatter dateFormatter,
DateFormatter jodaDateFormatter) {
String javaTimeOut = dateFormatter.format(javaDate);
String jodaTimeOut = jodaDateFormatter.formatJoda(jodaDate);

assertThat(jodaDate.getMillis(), is(javaDate.toInstant().toEpochMilli()));
String javaTimeOut = DateFormatter.forPattern(format).format(javaDate);
String jodaTimeOut = Joda.forPattern(format).formatJoda(jodaDate);

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

private void assertSameDate(String input, String format, Locale locale) {
DateFormatter jodaFormatter = Joda.forPattern(format).withLocale(locale);
DateFormatter javaFormatter = DateFormatter.forPattern(format).withLocale(locale);
assertSameDate(input, format, jodaFormatter, javaFormatter);
}

private void assertSameDate(String input, String format, DateFormatter jodaFormatter, DateFormatter javaFormatter) {
DateTime jodaDateTime = jodaFormatter.parseJoda(input);

Expand Down

0 comments on commit e95b0c4

Please sign in to comment.