private ParseResult parse()

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);
    }