in server/src/main/java/org/elasticsearch/common/time/Iso8601Parser.java [202:416]
private ParseResult parse(CharSequence str, @Nullable ZoneId defaultTimezone) {
int len = str.length();
// YEARS
Integer years = parseInt(str, 0, 4);
if (years == null) return ParseResult.error(0);
if (len == 4) {
return isOptional(ChronoField.MONTH_OF_YEAR)
? new ParseResult(
withZoneOffset(
years,
defaults.get(ChronoField.MONTH_OF_YEAR),
defaults.get(ChronoField.DAY_OF_MONTH),
defaults.get(ChronoField.HOUR_OF_DAY),
defaults.get(ChronoField.MINUTE_OF_HOUR),
defaults.get(ChronoField.SECOND_OF_MINUTE),
defaults.get(ChronoField.NANO_OF_SECOND),
defaultTimezone
)
)
: ParseResult.error(4);
}
if (str.charAt(4) != '-' || maxAllowedField == ChronoField.YEAR) return ParseResult.error(4);
// MONTHS
Integer months = parseInt(str, 5, 7);
if (months == null || months > 12) return ParseResult.error(5);
if (len == 7) {
return isOptional(ChronoField.DAY_OF_MONTH)
? new ParseResult(
withZoneOffset(
years,
months,
defaults.get(ChronoField.DAY_OF_MONTH),
defaults.get(ChronoField.HOUR_OF_DAY),
defaults.get(ChronoField.MINUTE_OF_HOUR),
defaults.get(ChronoField.SECOND_OF_MINUTE),
defaults.get(ChronoField.NANO_OF_SECOND),
defaultTimezone
)
)
: ParseResult.error(7);
}
if (str.charAt(7) != '-' || maxAllowedField == ChronoField.MONTH_OF_YEAR) return ParseResult.error(7);
// DAYS
Integer days = parseInt(str, 8, 10);
if (days == null || days > 31) return ParseResult.error(8);
if (len == 10) {
return optionalTime || isOptional(ChronoField.HOUR_OF_DAY)
? new ParseResult(
withZoneOffset(
years,
months,
days,
defaults.get(ChronoField.HOUR_OF_DAY),
defaults.get(ChronoField.MINUTE_OF_HOUR),
defaults.get(ChronoField.SECOND_OF_MINUTE),
defaults.get(ChronoField.NANO_OF_SECOND),
defaultTimezone
)
)
: ParseResult.error(10);
}
if (str.charAt(10) != 'T' || maxAllowedField == ChronoField.DAY_OF_MONTH) return ParseResult.error(10);
if (len == 11) {
return isOptional(ChronoField.HOUR_OF_DAY)
? new ParseResult(
withZoneOffset(
years,
months,
days,
defaults.get(ChronoField.HOUR_OF_DAY),
defaults.get(ChronoField.MINUTE_OF_HOUR),
defaults.get(ChronoField.SECOND_OF_MINUTE),
defaults.get(ChronoField.NANO_OF_SECOND),
defaultTimezone
)
)
: ParseResult.error(11);
}
// HOURS + timezone
Integer hours = parseInt(str, 11, 13);
if (hours == null || hours > 23) return ParseResult.error(11);
if (len == 13) {
return isOptional(ChronoField.MINUTE_OF_HOUR) && timezonePresence != TimezonePresence.MANDATORY
? new ParseResult(
withZoneOffset(
years,
months,
days,
hours,
defaultZero(ChronoField.MINUTE_OF_HOUR),
defaultZero(ChronoField.SECOND_OF_MINUTE),
defaultZero(ChronoField.NANO_OF_SECOND),
defaultTimezone
)
)
: ParseResult.error(13);
}
if (isZoneId(str, 13)) {
ZoneId timezone = parseZoneId(str, 13);
return timezone != null && isOptional(ChronoField.MINUTE_OF_HOUR)
? new ParseResult(
withZoneOffset(
years,
months,
days,
hours,
defaultZero(ChronoField.MINUTE_OF_HOUR),
defaultZero(ChronoField.SECOND_OF_MINUTE),
defaultZero(ChronoField.NANO_OF_SECOND),
timezone
)
)
: ParseResult.error(13);
}
if (str.charAt(13) != ':' || maxAllowedField == ChronoField.HOUR_OF_DAY) return ParseResult.error(13);
// MINUTES + timezone
Integer minutes = parseInt(str, 14, 16);
if (minutes == null || minutes > 59) return ParseResult.error(14);
if (len == 16) {
return isOptional(ChronoField.SECOND_OF_MINUTE) && timezonePresence != TimezonePresence.MANDATORY
? new ParseResult(
withZoneOffset(
years,
months,
days,
hours,
minutes,
defaultZero(ChronoField.SECOND_OF_MINUTE),
defaultZero(ChronoField.NANO_OF_SECOND),
defaultTimezone
)
)
: ParseResult.error(16);
}
if (isZoneId(str, 16)) {
ZoneId timezone = parseZoneId(str, 16);
return timezone != null && isOptional(ChronoField.SECOND_OF_MINUTE)
? new ParseResult(
withZoneOffset(
years,
months,
days,
hours,
minutes,
defaultZero(ChronoField.SECOND_OF_MINUTE),
defaultZero(ChronoField.NANO_OF_SECOND),
timezone
)
)
: ParseResult.error(16);
}
if (str.charAt(16) != ':' || maxAllowedField == ChronoField.MINUTE_OF_HOUR) return ParseResult.error(16);
// SECONDS + timezone
Integer seconds = parseInt(str, 17, 19);
if (seconds == null || seconds > 59) return ParseResult.error(17);
if (len == 19) {
return isOptional(ChronoField.NANO_OF_SECOND) && timezonePresence != TimezonePresence.MANDATORY
? new ParseResult(
withZoneOffset(years, months, days, hours, minutes, seconds, defaultZero(ChronoField.NANO_OF_SECOND), defaultTimezone)
)
: ParseResult.error(19);
}
if (isZoneId(str, 19)) {
ZoneId timezone = parseZoneId(str, 19);
return timezone != null
? new ParseResult(
withZoneOffset(years, months, days, hours, minutes, seconds, defaultZero(ChronoField.NANO_OF_SECOND), timezone)
)
: ParseResult.error(19);
}
if (checkDecimalSeparator(str.charAt(19)) == false || maxAllowedField == ChronoField.SECOND_OF_MINUTE) return ParseResult.error(19);
// NANOS + timezone
// the last number could be millis or nanos, or any combination in the middle
// so we keep parsing numbers until we get to not a number
int nanos = 0;
int pos;
for (pos = 20; pos < len && pos < 29; pos++) {
char c = str.charAt(pos);
if (c < ZERO || c > NINE) break;
nanos = nanos * 10 + (c - ZERO);
}
if (pos == 20) return ParseResult.error(20); // didn't find a number at all
// multiply it by the correct multiplicand to get the nanos
nanos *= NANO_MULTIPLICANDS[29 - pos];
if (len == pos) {
return timezonePresence != TimezonePresence.MANDATORY
? new ParseResult(withZoneOffset(years, months, days, hours, minutes, seconds, nanos, defaultTimezone))
: ParseResult.error(pos);
}
if (isZoneId(str, pos)) {
ZoneId timezone = parseZoneId(str, pos);
return timezone != null
? new ParseResult(withZoneOffset(years, months, days, hours, minutes, seconds, nanos, timezone))
: ParseResult.error(pos);
}
// still chars left at the end - string is not valid
return ParseResult.error(pos);
}