private static Object[] parseOffsetPattern(String pattern, String letters) {
        boolean isPrevQuote = false;
        boolean inQuote = false;
        StringBuilder text = new StringBuilder();
        char itemType = 0;  // 0 for string literal, otherwise time pattern character
        int itemLength = 1;
        boolean invalidPattern = false;

        List<Object> items = new ArrayList<Object>();
        BitSet checkBits = new BitSet(letters.length());

        for (int i = 0; i < pattern.length(); i++) {
            char ch = pattern.charAt(i);
            if (ch == '\'') {
                if (isPrevQuote) {
                    text.append('\'');
                    isPrevQuote = false;
                } else {
                    isPrevQuote = true;
                    if (itemType != 0) {
                        if (GMTOffsetField.isValid(itemType, itemLength)) {
                            items.add(new GMTOffsetField(itemType, itemLength));
                        } else {
                            invalidPattern = true;
                            break;
                        }
                        itemType = 0;
                    }
                }
                inQuote = !inQuote;
            } else {
                isPrevQuote = false;
                if (inQuote) {
                    text.append(ch);
                } else {
                    int patFieldIdx = letters.indexOf(ch);
                    if (patFieldIdx >= 0) {
                        // an offset time pattern character
                        if (ch == itemType) {
                            itemLength++;
                        } else {
                            if (itemType == 0) {
                                if (text.length() > 0) {
                                    items.add(text.toString());
                                    text.setLength(0);
                                }
                            } else {
                                if (GMTOffsetField.isValid(itemType, itemLength)) {
                                    items.add(new GMTOffsetField(itemType, itemLength));
                                } else {
                                    invalidPattern = true;
                                    break;
                                }
                            }
                            itemType = ch;
                            itemLength = 1;
                            checkBits.set(patFieldIdx);
                        }
                    } else {
                        // a string literal
                        if (itemType != 0) {
                            if (GMTOffsetField.isValid(itemType, itemLength)) {
                                items.add(new GMTOffsetField(itemType, itemLength));
                            } else {
                                invalidPattern = true;
                                break;
                            }
                            itemType = 0;
                        }
                        text.append(ch);
                    }
                }
            }
        }
        // handle last item
        if (!invalidPattern) {
            if (itemType == 0) {
                if (text.length() > 0) {
                    items.add(text.toString());
                    text.setLength(0);
                }
            } else {
                if (GMTOffsetField.isValid(itemType, itemLength)) {
                    items.add(new GMTOffsetField(itemType, itemLength));
                } else {
                    invalidPattern = true;
                }
            }
        }

        if (invalidPattern || checkBits.cardinality() != letters.length()) {
            throw new IllegalStateException("Bad localized GMT offset pattern: " + pattern);
        }

        return items.toArray(new Object[items.size()]);
    }
private static Object [ ] parseOffsetPattern ( String pattern , String letters ) { boolean isPrevQuote = false ; boolean inQuote = false ; StringBuilder text = new StringBuilder ( ) ; char itemType = 0 ; int itemLength = 1 ; boolean invalidPattern = false ; List < Object > items = new ArrayList < Object > ( ) ; BitSet checkBits = new BitSet ( letters . length ( ) ) ; for ( int i = 0 ; i < pattern . length ( ) ; i ++ ) { char ch = pattern . charAt ( i ) ; if ( ch == '\'' ) { if ( isPrevQuote ) { text . append ( '\'' ) ; isPrevQuote = false ; } else { isPrevQuote = true ; if ( itemType != 0 ) { if ( GMTOffsetField . isValid ( itemType , itemLength ) ) { items . add ( new GMTOffsetField ( itemType , itemLength ) ) ; } else { invalidPattern = true ; break ; } itemType = 0 ; } } inQuote = ! inQuote ; } else { isPrevQuote = false ; if ( inQuote ) { text . append ( ch ) ; } else { int patFieldIdx = letters . indexOf ( ch ) ; if ( patFieldIdx >= 0 ) { if ( ch == itemType ) { itemLength ++ ; } else { if ( itemType == 0 ) { if ( text . length ( ) > 0 ) { items . add ( text . toString ( ) ) ; text . setLength ( 0 ) ; } } else { if ( GMTOffsetField . isValid ( itemType , itemLength ) ) { items . add ( new GMTOffsetField ( itemType , itemLength ) ) ; } else { invalidPattern = true ; break ; } } itemType = ch ; itemLength = 1 ; checkBits . set ( patFieldIdx ) ; } } else { if ( itemType != 0 ) { if ( GMTOffsetField . isValid ( itemType , itemLength ) ) { items . add ( new GMTOffsetField ( itemType , itemLength ) ) ; } else { invalidPattern = true ; break ; } itemType = 0 ; } text . append ( ch ) ; } } } } if ( ! invalidPattern ) { if ( itemType == 0 ) { if ( text . length ( ) > 0 ) { items . add ( text . toString ( ) ) ; text . setLength ( 0 ) ; } } else { if ( GMTOffsetField . isValid ( itemType , itemLength ) ) { items . add ( new GMTOffsetField ( itemType , itemLength ) ) ; } else { invalidPattern = true ; } } } if ( invalidPattern || checkBits . cardinality ( ) != letters . length ( ) ) { throw new IllegalStateException ( "Bad localized GMT offset pattern: " + pattern ) ; } return items . toArray ( new Object [ items . size ( ) ] ) ; }
Parse the GMT offset pattern into runtime optimized format

@param pattern the offset pattern string
@param letters the required pattern letters such as "Hm"
@return An array of Object. Each array entry is either String (representing
pattern literal) or GMTOffsetField (hour/min/sec field)