public int fromDateFormatStr()

in fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java [1278:1658]


    public int fromDateFormatStr(String format, String value, boolean hasSubVal) throws InvalidFormatException {
        int pFormat = 0; // pointer to the current format string
        int endFormat = format.length(); // end of format string
        int pValue = 0; // pointer to the date string value
        int endValue = value.length(); // end of date string value

        int partUsed = 0;
        final int yearPart = 1 << 0;
        final int monthPart = 1 << 1;
        final int dayPart = 1 << 2;
        final int weekdayPart = 1 << 3;
        final int yeardayPart = 1 << 4;
        final int weekNumPart = 1 << 5;
        final int normalDatePart = yearPart | monthPart | dayPart;
        final int specialDatePart = weekdayPart | yeardayPart | weekNumPart;
        final int datePart = normalDatePart | specialDatePart;
        final int hourPart = 1 << 6;
        final int minutePart = 1 << 7;
        final int secondPart = 1 << 8;
        final int fracPart = 1 << 9;
        final int timePart = hourPart | minutePart | secondPart | fracPart;

        int halfDay = 0; // 0 for am/none, 12 for pm.
        long weekday = -1;
        long yearday = -1;
        long weekNum = -1;

        boolean strictWeekNumber = false;
        boolean sundayFirst = false;
        boolean strictWeekNumberYearType = false;
        long strictWeekNumberYear = -1;
        boolean hourSystem12 = false; // hour in [0..12] and with am/pm

        char now;
        while (pFormat < endFormat && pValue < endValue) {
            // Skip space character
            while (pValue < endValue && Character.isSpaceChar(value.charAt(pValue))) {
                pValue++;
            }
            if (pValue >= endValue) {
                break;
            }

            // Check switch
            now = format.charAt(pFormat);
            if (now == '%' && pFormat + 1 < endFormat) {
                int tmp = 0;
                long intValue = 0;
                pFormat++;
                now = format.charAt(pFormat);
                pFormat++;
                switch (now) {
                    // Year
                    case 'y':
                        // Year, numeric (two digits)
                        tmp = pValue + Math.min(2, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        intValue += intValue >= 70 ? 1900 : 2000;
                        this.year = intValue;
                        pValue = tmp;
                        partUsed |= yearPart;
                        break;
                    case 'Y':
                        // Year, numeric, four digits
                        tmp = pValue + Math.min(4, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        if (tmp - pValue <= 2) {
                            intValue += intValue >= 70 ? 1900 : 2000;
                        }
                        this.year = intValue;
                        pValue = tmp;
                        partUsed |= yearPart;
                        break;
                    // Month
                    case 'm':
                    case 'c':
                        tmp = pValue + Math.min(2, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        this.month = intValue;
                        pValue = tmp;
                        partUsed |= monthPart;
                        break;
                    case 'M': {
                        int nextPos = findWord(value, pValue);
                        intValue = checkWord(MONTH_NAME_DICT, value.substring(pValue, nextPos));
                        this.month = intValue;
                        pValue = nextPos;
                        partUsed |= monthPart;
                        break;
                    }
                    case 'b': {
                        int nextPos = findWord(value, pValue);
                        intValue = checkWord(MONTH_ABBR_NAME_DICT, value.substring(pValue, nextPos));
                        this.month = intValue;
                        pValue = nextPos;
                        partUsed |= monthPart;
                        break;
                    }
                    // Day
                    case 'd':
                    case 'e':
                        tmp = pValue + Math.min(2, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        this.day = intValue;
                        pValue = tmp;
                        partUsed |= dayPart;
                        break;
                    case 'D':
                        tmp = pValue + Math.min(2, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        this.day = intValue;
                        pValue = tmp + Math.min(2, endValue - tmp);
                        partUsed |= dayPart;
                        break;
                    // Hour
                    case 'h':
                    case 'I':
                    case 'l':
                        hourSystem12 = true;
                        partUsed |= hourPart;
                    case 'k': // CHECKSTYLE IGNORE THIS LINE: Fall through
                    case 'H':
                        tmp = findNumber(value, pValue, 2);
                        intValue = strToLong(value.substring(pValue, tmp));
                        this.hour = intValue;
                        pValue = tmp;
                        partUsed |= hourPart;
                        break;
                    // Minute
                    case 'i':
                        tmp = pValue + Math.min(2, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        this.minute = intValue;
                        pValue = tmp;
                        partUsed |= minutePart;
                        break;
                    // Second
                    case 's':
                    case 'S':
                        tmp = pValue + Math.min(2, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        this.second = intValue;
                        pValue = tmp;
                        partUsed |= secondPart;
                        break;
                    // Micro second
                    case 'f':
                        tmp = pValue;
                        // when there's still something to the end, fix the scale of ms.
                        while (tmp < endValue && Character.isDigit(value.charAt(tmp))) {
                            tmp += 1;
                        }

                        if (tmp - pValue > 6) {
                            int tmp2 = pValue + 6;
                            intValue = strToLong(value.substring(pValue, tmp2));
                        } else {
                            intValue = strToLong(value.substring(pValue, tmp));
                        }
                        this.microsecond = (long) (intValue * Math.pow(10, 6 - Math.min(6, tmp - pValue)));
                        partUsed |= fracPart;
                        pValue = tmp;
                        break;
                    // AM/PM
                    case 'p':
                        if ((endValue - pValue) < 2 || Character.toUpperCase(value.charAt(pValue + 1)) != 'M'
                                || !hourSystem12) {
                            throw new InvalidFormatException("Invalid %p format");
                        }
                        if (Character.toUpperCase(value.charAt(pValue)) == 'P') {
                            // PM
                            halfDay = 12;
                        }
                        pValue += 2;
                        break;
                    // Weekday
                    case 'W': {
                        int nextPos = findWord(value, pValue);
                        intValue = checkWord(WEEK_DAY_NAME_DICT, value.substring(pValue, nextPos));
                        intValue++;
                        weekday = intValue;
                        partUsed |= weekdayPart;
                        break;
                    }
                    case 'a': {
                        int nextPos = findWord(value, pValue);
                        intValue = checkWord(WEEK_DAY_NAME_DICT, value.substring(pValue, nextPos));
                        intValue++;
                        weekday = intValue;
                        partUsed |= weekdayPart;
                        break;
                    }
                    case 'w':
                        tmp = pValue + Math.min(1, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        if (intValue >= 7) {
                            throw new InvalidFormatException("invalid day of week: " + intValue);
                        }
                        if (intValue == 0) {
                            intValue = 7;
                        }
                        weekday = intValue;
                        pValue = tmp;
                        partUsed |= weekdayPart;
                        break;
                    case 'j':
                        tmp = pValue + Math.min(3, endValue - pValue);
                        intValue = strToLong(value.substring(pValue, tmp));
                        yearday = intValue;
                        pValue = tmp;
                        partUsed |= yeardayPart;
                        break;
                    case 'u':
                    case 'v':
                    case 'U':
                    case 'V':
                        sundayFirst = (format.charAt(pFormat - 1) == 'U' || format.charAt(pFormat - 1) == 'V');
                        // Used to check if there is %x or %X
                        strictWeekNumber = (format.charAt(pFormat - 1) == 'V' || format.charAt(pFormat - 1) == 'v');
                        tmp = pValue + Math.min(2, endValue - pValue);
                        intValue = Long.valueOf(value.substring(pValue, tmp));
                        weekNum = intValue;
                        if (weekNum > 53 || (strictWeekNumber && weekNum == 0)) {
                            throw new InvalidFormatException("invalid num of week: " + weekNum);
                        }
                        pValue = tmp;
                        partUsed |= weekNumPart;
                        break;
                    // strict week number, must be used with %V or %v
                    case 'x':
                    case 'X':
                        strictWeekNumberYearType = (format.charAt(pFormat - 1) == 'X');
                        tmp = pValue + Math.min(4, endValue - pValue);
                        intValue = Long.valueOf(value.substring(pValue, tmp));
                        strictWeekNumberYear = intValue;
                        pValue = tmp;
                        partUsed |= weekNumPart;
                        break;
                    case 'r':
                        tmp = fromDateFormatStr("%I:%i:%S %p", value.substring(pValue, endValue), true);
                        pValue = tmp;
                        partUsed |= timePart;
                        break;
                    case 'T':
                        tmp = fromDateFormatStr("%H:%i:%S", value.substring(pValue, endValue), true);
                        pValue = tmp;
                        partUsed |= timePart;
                        break;
                    case '.':
                        while (pValue < endValue && Character.toString(value.charAt(pValue)).matches("\\p{Punct}")) {
                            pValue++;
                        }
                        break;
                    case '@':
                        while (pValue < endValue && Character.isLetter(value.charAt(pValue))) {
                            pValue++;
                        }
                        break;
                    case '#':
                        while (pValue < endValue && Character.isDigit(value.charAt(pValue))) {
                            pValue++;
                        }
                        break;
                    case '%': // %%, escape the %
                        if ('%' != value.charAt(pValue)) {
                            throw new InvalidFormatException("invalid char after %: " + value.charAt(pValue));
                        }
                        pValue++;
                        break;
                    default:
                        throw new InvalidFormatException("Invalid format pattern: " + now);
                }
            } else if (format.charAt(pFormat) != ' ') {
                if (format.charAt(pFormat) != value.charAt(pValue)) {
                    throw new InvalidFormatException("Invalid char: " + value.charAt(pValue) + ", expected: "
                        + format.charAt(pFormat));
                }
                pFormat++;
                pValue++;
            } else {
                pFormat++;
            }
        }

        // continue to iterate pattern if has
        // to find out if it has time part.
        while (pFormat < endFormat) {
            now = format.charAt(pFormat);
            if (now == '%' && pFormat + 1 < endFormat) {
                pFormat++;
                now = format.charAt(pFormat);
                pFormat++;
                switch (now) {
                    case 'H':
                    case 'h':
                    case 'I':
                    case 'i':
                    case 'k':
                    case 'l':
                    case 'r':
                    case 's':
                    case 'S':
                    case 'p':
                    case 'T':
                        partUsed |= timePart;
                        break;
                    default:
                        break;
                }
            } else {
                pFormat++;
            }
        }

        if (partUsed == 0) {
            throw new InvalidFormatException("Nothing for legal Date: " + value);
        }

        if (hourSystem12) {
            if (this.hour > 12 || this.hour < 1) {
                throw new InvalidFormatException("Invalid hour: " + hour);
            }
            this.hour = (this.hour % 12) + halfDay;
        }

        if (hasSubVal) {
            return pValue;
        }

        // Year day
        if (yearday > 0) {
            long days = calcDaynr(this.year, 1, 1) + yearday - 1;
            getDateFromDaynr(days);
        }

        // weekday
        if (weekNum >= 0 && weekday > 0) {
            // Check
            if ((strictWeekNumber && (strictWeekNumberYear < 0
                    || strictWeekNumberYearType != sundayFirst))
                    || (!strictWeekNumber && strictWeekNumberYear >= 0)) {
                throw new InvalidFormatException("invalid week number");
            }
            long days = calcDaynr(strictWeekNumber ? strictWeekNumberYear : this.year, 1, 1);

            long weekdayB = calcWeekday(days, sundayFirst);

            if (sundayFirst) {
                days += ((weekdayB == 0) ? 0 : 7) - weekdayB + (weekNum - 1) * 7 + weekday % 7;
            } else {
                days += ((weekdayB <= 3) ? 0 : 7) - weekdayB + (weekNum - 1) * 7 + weekday - 1;
            }
            getDateFromDaynr(days);
        }

        // complete default month/day
        if ((partUsed & ~normalDatePart) == 0) { // only date here
            if ((partUsed & dayPart) == 0) {
                day = 1;
                if ((partUsed & monthPart) == 0) {
                    month = 1;
                }
            }
        }

        // Compute timestamp type
        if ((partUsed & datePart) != 0) { // Ymd part only
            if ((partUsed & fracPart) != 0) {
                this.type = Type.DATETIMEV2_WITH_MAX_SCALAR;
            } else if ((partUsed & timePart) != 0) {
                this.type = ScalarType.getDefaultDateType(Type.DATETIME);
            } else {
                this.type = ScalarType.getDefaultDateType(Type.DATE);
            }
        }

        if (checkRange() || checkDate()) {
            throw new InvalidFormatException("Invalid format");
        }
        return 0;
    }