Triple validateAndConvertTimeZone()

in src/main/java/com/aliyun/dts/subscribe/clients/record/value/DateTime.java [432:622]


    Triple<Boolean, StringBuilder, StringBuilder> validateAndConvertTimeZone(String timeZone) {
        if (StringUtils.isEmpty(timeZone)) {
            return Triple.of(false, null, null);
        }

        char charValue;
        boolean isLegalTimeZone = false;
        int index = 0;
        final int totalLength = timeZone.length();
        final StringBuilder sbl = new StringBuilder(16);
        final StringBuilder tzSbl = new StringBuilder(16);
        charValue = timeZone.charAt(index);

        check_and_fix:
        {
            // check first letter
            switch (charValue) {
                case 'G':
                    if ('M' != timeZone.charAt(++index)) {
                        break check_and_fix;
                    }
                    if ('T' != timeZone.charAt(++index)) {
                        break check_and_fix;
                    }
                    tzSbl.append("GMT");
                    ++index;
                    break;
                case 'U':
                    // short path for UTC
                    if ('T' != timeZone.charAt(++index)) {
                        break check_and_fix;
                    }
                    if ('C' != timeZone.charAt(++index)) {
                        break check_and_fix;
                    }
                    tzSbl.append("UTC");
                    ++index;
                    break;
                case '+':
                case '-':
                    // add default timezone specification
                    tzSbl.append("GMT");
                    break;
                default:
                    if ('0' <= charValue && '9' >= charValue) {
                        tzSbl.append("GMT");
                        break;
                    } else {
                        final String tmpOffset = timeZoneOffsets.getOrDefault(timeZone.toLowerCase(), null);
                        if (null == tmpOffset) {
                            break check_and_fix;
                        } else {
                            // special time zone, convert it to time offset
                            isLegalTimeZone = true;
                            sbl.append(tmpOffset);
                            tzSbl.append(timeZone);
                            break check_and_fix;
                        }
                    }
            }

            // check remaining letters
            /**
             * we use a state machine to do the checking and fixing:
             *
             *                       SUCCESS_FIN <---| <-----------------|
             *                           ^           |                   |
             *                          e|           |e                  |e
             *                   0~9     |     0~9   |    :        0~9   |    0~9       :         0~9       0~9       e
             * 0 --------> 1 ----------> 2 --------> 3 ------> 4 ------> 5 ------> 6 -------> 7 ------> 8 ------> 9 ----> SUCCESS_FIN
             * |                       |  |               ^
             * |                       |  |       :       |
             * |                       |  |---------------|
             * |                       |
             * |      others           V
             * |--------------> ERROR_FIN
             */
            int processingState = 0;
            while (index < totalLength) {
                charValue = timeZone.charAt(index++);
                switch (processingState) {
                    case 0:
                        if (' ' == charValue) {
                            processingState = 0;
                        } else if ('+' == charValue || '-' == charValue) {
                            sbl.append(charValue);
                            processingState = 1;
                        } else if ('0' <= charValue && '9' >= charValue) {
                            sbl.append("+");
                            sbl.append(charValue);
                            processingState = 2;
                        } else {
                            break check_and_fix;
                        }
                        break;
                    case 1:
                        if ('0' <= charValue && '9' >= charValue) {
                            sbl.append(charValue);
                            processingState = 2;
                        } else {
                            break check_and_fix;
                        }
                        break;
                    case 2:
                        if ('0' <= charValue && '9' >= charValue) {
                            sbl.append(charValue);
                            processingState = 3;
                        } else if (':' == charValue) {
                            sbl.insert(sbl.length() - 1, '0');
                            sbl.append(charValue);
                            processingState = 4;
                        } else {
                            break check_and_fix;
                        }
                        break;
                    case 3:
                        if (':' == charValue) {
                            sbl.append(charValue);
                            processingState = 4;
                        } else {
                            break check_and_fix;
                        }
                        break;
                    case 4:
                        if ('0' <= charValue && '9' >= charValue) {
                            sbl.append(charValue);
                            processingState = 5;
                        } else {
                            break check_and_fix;
                        }
                        break;
                    case 5:
                        if ('0' <= charValue && '9' >= charValue) {
                            sbl.append(charValue);
                            processingState = 6;
                        } else {
                            break check_and_fix;
                        }
                        break;
                    case 6:
                        if (':' == charValue) {
                            processingState = 7;
                            sbl.append(charValue);
                        } else {
                            break check_and_fix;
                        }
                        break;
                    case 7:
                        if ('0' <= charValue && '9' >= charValue) {
                            sbl.append(charValue);
                            processingState = 8;
                        } else {
                            break check_and_fix;
                        }
                        break;
                    case 8:
                        if ('0' <= charValue && '9' >= charValue) {
                            sbl.append(charValue);
                            processingState = 9;
                        } else {
                            break check_and_fix;
                        }
                        break;
                    default:
                        break check_and_fix;
                }
            }
            // here we process the e input for state
            switch (processingState) {
                case 0:
                    sbl.append('+');
                    sbl.append('0');
                case 2:
                    sbl.insert(sbl.length() - 1, '0');
                case 3:
                    sbl.append(":00");
                    tzSbl.append(sbl);
                    isLegalTimeZone = true;
                    break;
                case 5:
                case 8:
                    sbl.insert(sbl.length() - 1, '0');
                case 6:
                case 9:
                    tzSbl.append(sbl);
                    isLegalTimeZone = true;
                    break;
            }
        }
        return Triple.of(isLegalTimeZone, sbl, tzSbl);
    }