public boolean parseDateTime()

in asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/DateTimeFormatUtils.java [311:987]


    public boolean parseDateTime(AMutableInt64 outChronon, Mutable<Boolean> outTimeZoneExists,
            AMutableInt32 outTimeZone, Mutable<Character> dateTimeSeparatorOut, byte[] data, int dataStart,
            int dataLength, byte[] format, int formatStart, int formatLength, DateTimeParseMode parseMode,
            boolean raiseParseDataError, char altSeparatorChar, boolean adjustChrononByTimezone)
            throws AsterixTemporalTypeParseException {
        int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, ms = 0, timezone = 0;
        boolean timezoneExists = false;

        boolean negativeYear = false;
        int formatCharCopies;

        int dataStringPointer = 0, formatPointer = 0;

        char separatorChar = '\0';

        char lastSeparatorChar = '\0';

        char dateTimeSeparatorChar = 'T'; //default dateTimeSeparator

        DateTimeProcessState processState;

        int pointerMove;

        while (dataStringPointer < dataLength && formatPointer < formatLength) {
            formatCharCopies = 0;
            switch (format[formatStart + formatPointer]) {
                case YEAR_CHAR:
                    processState = DateTimeProcessState.YEAR;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, YEAR_CHAR,
                            MAX_YEAR_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case QUARTER_CHAR:
                    processState = DateTimeProcessState.QUARTER;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, QUARTER_CHAR,
                            MAX_QUARTER_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case MONTH_CHAR:
                    processState = DateTimeProcessState.MONTH;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, MONTH_CHAR,
                            MAX_MONTH_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case DAY_CHAR:
                    processState = DateTimeProcessState.DAY;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, DAY_CHAR,
                            MAX_DAY_CHARS_PARSE);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case WEEKDAY_CHAR:
                    processState = DateTimeProcessState.WEEKDAY;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, WEEKDAY_CHAR,
                            MAX_WEEKDAY_CHAR);
                    if (pointerMove < MIN_WEEKDAY_CHAR) {
                        throw new AsterixTemporalTypeParseException(
                                String.format("Expected at least %d '%s' characters but got %d", MIN_WEEKDAY_CHAR,
                                        WEEKDAY_CHAR, pointerMove));
                    }
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case HOUR_CHAR:
                    processState = DateTimeProcessState.HOUR;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, HOUR_CHAR,
                            MAX_HOUR_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case MINUTE_CHAR:
                    processState = DateTimeProcessState.MINUTE;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, MINUTE_CHAR,
                            MAX_MINUTE_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case SECOND_CHAR:
                    processState = DateTimeProcessState.SECOND;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, SECOND_CHAR,
                            MAX_SECOND_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case MILLISECOND_CHAR:
                    processState = DateTimeProcessState.MILLISECOND;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, MILLISECOND_CHAR,
                            MAX_MILLISECOND_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case MILLISECOND_CHAR_ALT:
                    processState = DateTimeProcessState.MILLISECOND;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer,
                            MILLISECOND_CHAR_ALT, MAX_MILLISECOND_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case AMPM_CHAR:
                    processState = DateTimeProcessState.AMPM;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, AMPM_CHAR,
                            MAX_AMPM_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;

                case TIMEZONE_CHAR:
                    processState = DateTimeProcessState.TIMEZONE;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, TIMEZONE_CHAR,
                            MAX_TIMEZONE_CHARS);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case SKIPPER_CHAR:
                    processState = DateTimeProcessState.SKIPPER;
                    pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, SKIPPER_CHAR,
                            MAX_SKIPPER_CHAR);
                    formatPointer += pointerMove;
                    formatCharCopies += pointerMove;
                    break;
                case ' ':
                case HYPHEN_CHAR:
                case COLON_CHAR:
                case SOLIDUS_CHAR:
                case PERIOD_CHAR:
                case COMMA_CHAR:
                case T_CHAR:
                    // separator
                    separatorChar = (char) format[formatStart + formatPointer];
                    processState = DateTimeProcessState.SEPARATOR;
                    formatPointer++;
                    formatCharCopies++;
                    while (formatPointer < formatLength
                            && (char) (format[formatStart + formatPointer]) == separatorChar) {
                        formatPointer++;
                        formatCharCopies++;
                    }
                    break;

                default:
                    throw new AsterixTemporalTypeParseException("Unexpected date format string at "
                            + (formatStart + formatPointer) + ": " + (char) format[formatStart + formatPointer]);
            }

            // check whether the process state is valid for the parse mode

            switch (processState) {
                case YEAR:
                case QUARTER:
                case MONTH:
                case DAY:
                    if (parseMode == DateTimeParseMode.TIME_ONLY) {
                        throw new AsterixTemporalTypeParseException(
                                "Unexpected date format string when parsing a time value");
                    }
                    break;
                case HOUR:
                case MINUTE:
                case SECOND:
                case MILLISECOND:
                case AMPM:
                case TIMEZONE:
                    if (parseMode == DateTimeParseMode.DATE_ONLY) {
                        throw new AsterixTemporalTypeParseException(
                                "Unexpected time format string when parsing a date value");
                    }
                    break;
                default:
                    // do nothing
            }

            switch (processState) {
                case YEAR:
                    if (dataStringPointer < dataLength && data[dataStart + dataStringPointer] == HYPHEN_CHAR) {
                        negativeYear = true;
                        dataStringPointer++;
                    }
                case DAY:
                    int maxAllowedFormatCharCopies = (processState == DateTimeProcessState.YEAR) ? 4 : 2;
                    int parsedValue = 0;
                    int processedFieldsCount = 0;
                    for (int i = 0; i < formatCharCopies; i++) {
                        if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException("Unexpected char for year field at "
                                        + (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
                            } else {
                                return false;
                            }
                        }
                        parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                        dataStringPointer++;
                        processedFieldsCount++;
                    }
                    // for more digits
                    while (processedFieldsCount < maxAllowedFormatCharCopies && dataStringPointer < dataLength
                            && data[dataStart + dataStringPointer] >= '0'
                            && data[dataStart + dataStringPointer] <= '9') {
                        parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                        dataStringPointer++;
                        processedFieldsCount++;
                    }
                    if (processState == DateTimeProcessState.YEAR) {
                        year = parsedValue;
                        if (negativeYear) {
                            year *= -1;
                        }
                        // Allow month and day to be missing if we parsed year
                        if (month == 0) {
                            month = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.MONTH.ordinal()];
                        }
                        if (day == 0) {
                            day = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
                        }
                    } else {
                        if (parsedValue == 0) {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException(
                                        "Incorrect day value at " + (dataStart + dataStringPointer));
                            } else {
                                return false;
                            }
                        }
                        day = parsedValue;
                    }
                    break;
                case QUARTER:
                    // the month is in the number format
                    parsedValue = 0;
                    int processedQuarterFieldsCount = 0;
                    for (int i = 0; i < formatCharCopies; i++) {
                        if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException("Unexpected char for quarter field at "
                                        + (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
                            } else {
                                return false;
                            }
                        }
                        parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                        dataStringPointer++;
                        if (processedQuarterFieldsCount++ > 2) {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException("Unexpected char for quarter field at "
                                        + (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
                            } else {
                                return false;
                            }
                        }
                    }
                    // if there are more than 2 digits for the quarter string
                    while (processedQuarterFieldsCount < 2 && dataStringPointer < dataLength
                            && data[dataStart + dataStringPointer] >= '0'
                            && data[dataStart + dataStringPointer] <= '9') {
                        parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                        dataStringPointer++;
                        processedQuarterFieldsCount++;
                    }
                    if (parsedValue == 0) {
                        if (raiseParseDataError) {
                            throw new AsterixTemporalTypeParseException(
                                    "Incorrect quarter value at " + (dataStart + dataStringPointer));
                        } else {
                            return false;
                        }
                    }
                    month = (parsedValue - 1) * 3 + 1;
                    // Allow day to be missing if we parsed quarter
                    if (day == 0) {
                        day = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
                    }
                    break;
                case MONTH:
                    if (formatCharCopies >= 3) {
                        // the month is in the text format
                        int processedMonthFieldsCount = 0;
                        while (((dataStringPointer + processedMonthFieldsCount < dataLength)) && ((data[dataStart
                                + dataStringPointer + processedMonthFieldsCount] >= 'a'
                                && data[dataStart + dataStringPointer + processedMonthFieldsCount] <= 'z')
                                || (data[dataStart + dataStringPointer + processedMonthFieldsCount] >= 'A'
                                        && data[dataStart + dataStringPointer + processedMonthFieldsCount] <= 'Z'))) {
                            processedMonthFieldsCount++;
                        }
                        boolean useShortNames = formatCharCopies == 3;
                        int monthNameMatch = monthIDSearch(data, dataStart + dataStringPointer,
                                processedMonthFieldsCount, useShortNames);
                        if (monthNameMatch >= 0) {
                            month = monthNameMatch + 1;
                            dataStringPointer += processedMonthFieldsCount;
                        } else {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException(
                                        "Unrecognizable month string " + (char) data[dataStart + dataStringPointer]
                                                + " " + (char) data[dataStart + dataStringPointer + 1] + " "
                                                + (char) data[dataStart + dataStringPointer + 2]);
                            } else {
                                return false;
                            }
                        }
                    } else {
                        // the month is in the number format
                        parsedValue = 0;
                        int processedMonthFieldsCount = 0;
                        for (int i = 0; i < formatCharCopies; i++) {
                            if (data[dataStart + dataStringPointer] < '0'
                                    || data[dataStart + dataStringPointer] > '9') {
                                if (raiseParseDataError) {
                                    throw new AsterixTemporalTypeParseException(
                                            "Unexpected char for month field at " + (dataStart + dataStringPointer)
                                                    + ": " + data[dataStart + dataStringPointer]);
                                } else {
                                    return false;
                                }
                            }
                            parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                            dataStringPointer++;
                            if (processedMonthFieldsCount++ > 2) {
                                if (raiseParseDataError) {
                                    throw new AsterixTemporalTypeParseException(
                                            "Unexpected char for month field at " + (dataStart + dataStringPointer)
                                                    + ": " + data[dataStart + dataStringPointer]);
                                } else {
                                    return false;
                                }
                            }
                        }
                        // if there are more than 2 digits for the month string
                        while (processedMonthFieldsCount < 2 && dataStringPointer < dataLength
                                && data[dataStart + dataStringPointer] >= '0'
                                && data[dataStart + dataStringPointer] <= '9') {
                            parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                            dataStringPointer++;
                            processedMonthFieldsCount++;
                        }
                        if (parsedValue == 0) {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException(
                                        "Incorrect month value at " + (dataStart + dataStringPointer));
                            } else {
                                return false;
                            }
                        }
                        month = parsedValue;
                    }
                    // Allow day to be missing if we parsed month
                    if (day == 0) {
                        day = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
                    }
                    break;
                case WEEKDAY:
                    int processedWeekdayFieldsCount = 0;
                    while ((dataStringPointer + processedWeekdayFieldsCount < dataLength) && ((data[dataStart
                            + dataStringPointer + processedWeekdayFieldsCount] >= 'a'
                            && data[dataStart + dataStringPointer + processedWeekdayFieldsCount] <= 'z')
                            || (data[dataStart + dataStringPointer + processedWeekdayFieldsCount] >= 'A'
                                    && data[dataStart + dataStringPointer + processedWeekdayFieldsCount] <= 'Z'))) {
                        processedWeekdayFieldsCount++;
                    }
                    // match the weekday name
                    boolean useShortNames = formatCharCopies == 3;
                    int weekdayNameMatch = weekdayIDSearch(data, dataStart + dataStringPointer,
                            processedWeekdayFieldsCount, useShortNames);
                    if (weekdayNameMatch < 0) {
                        if (raiseParseDataError) {
                            throw new AsterixTemporalTypeParseException("Unexpected string for day-of-week: "
                                    + new String(data, dataStart + dataStringPointer,
                                            dataStart + dataStringPointer + processedWeekdayFieldsCount, ENCODING));
                        } else {
                            return false;
                        }
                    }
                    dataStringPointer += processedWeekdayFieldsCount;
                    break;
                case HOUR:
                    dateTimeSeparatorChar = lastSeparatorChar;
                case MINUTE:
                case SECOND:
                case MILLISECOND:
                    int processFieldsCount = 0;
                    int expectedMaxCount = (processState == DateTimeProcessState.MILLISECOND) ? 3 : 2;
                    parsedValue = 0;
                    for (int i = 0; i < formatCharCopies; i++) {
                        if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException("Unexpected char for " + processState.name()
                                        + " field at " + (dataStart + dataStringPointer) + ": "
                                        + data[dataStart + dataStringPointer]);
                            } else {
                                return false;
                            }

                        }
                        parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                        dataStringPointer++;
                        if (processFieldsCount++ > expectedMaxCount) {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException(
                                        "Unexpected char for " + processState.name() + " field at " + dataStringPointer
                                                + ": " + data[dataStart + dataStringPointer]);
                            } else {
                                return false;
                            }
                        }
                    }
                    // if there are more than formatCharCopies digits for the hour string
                    while (processFieldsCount < expectedMaxCount && dataStringPointer < dataLength
                            && data[dataStart + dataStringPointer] >= '0'
                            && data[dataStart + dataStringPointer] <= '9') {
                        parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                        dataStringPointer++;
                        processFieldsCount++;
                    }
                    if (processState == DateTimeProcessState.HOUR) {
                        hour = parsedValue;
                    } else if (processState == DateTimeProcessState.MINUTE) {
                        min = parsedValue;
                    } else if (processState == DateTimeProcessState.SECOND) {
                        sec = parsedValue;
                    } else if (processState == DateTimeProcessState.MILLISECOND) {
                        //read remaining millis values
                        while (dataStringPointer < dataLength && data[dataStart + dataStringPointer] >= '0'
                                && data[dataStart + dataStringPointer] <= '9') {
                            //parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
                            dataStringPointer++;
                            processFieldsCount++;
                        }
                        ms = parsedValue;
                        for (int i = processFieldsCount; i < 3; i++) {
                            ms *= 10;
                        }
                    }
                    break;
                case TIMEZONE:
                    if (data[dataStart + dataStringPointer] == 'Z'
                            && ((dataStringPointer + 1 >= dataLength) || (data[dataStart + dataStringPointer + 1] < 'A'
                                    && data[dataStart + dataStringPointer + 1] > 'Z'
                                    && data[dataStart + dataStringPointer + 1] < 'a'
                                    && data[dataStart + dataStringPointer + 1] > 'z'))) {
                        // UTC as Z
                        timezone = 0;
                        dataStringPointer++;
                    } else if ((data[dataStart + dataStringPointer] == '+'
                            || data[dataStart + dataStringPointer] == '-')
                            || (dataStringPointer + 3 < dataLength && (data[dataStart + dataStringPointer + 3] == '+'
                                    || data[dataStart + dataStringPointer + 3] == '-'))) {
                        // UTC+ or GMT+ format
                        if (dataStringPointer + 3 < dataLength && (byteArrayEqualToString(data,
                                dataStart + dataStringPointer, 3, UTC_BYTEARRAY)
                                || byteArrayEqualToString(data, dataStart + dataStringPointer, 3, GMT_BYTEARRAY))) {
                            dataStringPointer += 3;
                        }
                        // parse timezone as +zz:zz or +zzzz
                        boolean negativeTimeZone = false;
                        if (data[dataStart + dataStringPointer] == '-') {
                            negativeTimeZone = true;
                            dataStringPointer++;
                        } else if (data[dataStart + dataStringPointer] == '+') {
                            dataStringPointer++;
                        } else {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException(
                                        "Incorrect timezone hour field: expecting sign + or - but got: "
                                                + data[dataStart + dataStringPointer]);
                            } else {
                                return false;
                            }
                        }
                        parsedValue = 0;
                        // timezone hours
                        for (int i = 0; i < 2; i++) {
                            if (data[dataStart + dataStringPointer + i] >= '0'
                                    && data[dataStart + dataStringPointer + i] <= '9') {
                                parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer + i] - '0');
                            } else {
                                if (raiseParseDataError) {
                                    throw new AsterixTemporalTypeParseException(
                                            "Unexpected character for timezone hour field at "
                                                    + (dataStart + dataStringPointer) + ": "
                                                    + data[dataStart + dataStringPointer]);
                                } else {
                                    return false;
                                }
                            }
                        }
                        dataStringPointer += 2;
                        // skip the ":" separator
                        if (data[dataStart + dataStringPointer] == ':') {
                            dataStringPointer++;
                        }
                        timezone = (int) (parsedValue * GregorianCalendarSystem.CHRONON_OF_HOUR);
                        parsedValue = 0;
                        // timezone minutes
                        for (int i = 0; i < 2; i++) {
                            if (data[dataStart + dataStringPointer + i] >= '0'
                                    && data[dataStart + dataStringPointer + i] <= '9') {
                                parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer + i] - '0');
                            } else {
                                if (raiseParseDataError) {
                                    throw new AsterixTemporalTypeParseException(
                                            "Unexpected character for timezone minute field at "
                                                    + (dataStart + dataStringPointer) + ": "
                                                    + data[dataStart + dataStringPointer]);
                                } else {
                                    return false;
                                }
                            }
                        }
                        timezone += (int) (parsedValue * GregorianCalendarSystem.CHRONON_OF_MINUTE);
                        dataStringPointer += 2;
                        if (!negativeTimeZone) {
                            timezone *= -1;
                        }
                    } else {
                        // do lookup from the zoneinfor database
                        int timezoneEndField = dataStringPointer;
                        while (timezoneEndField < dataLength && ((data[dataStart + timezoneEndField] >= '0'
                                && data[dataStart + timezoneEndField] <= '9')
                                || (data[dataStart + timezoneEndField] >= 'a'
                                        && data[dataStart + timezoneEndField] <= 'z')
                                || (data[dataStart + timezoneEndField] >= 'A'
                                        && data[dataStart + timezoneEndField] <= 'Z')
                                || data[dataStart + timezoneEndField] == '/'
                                || data[dataStart + timezoneEndField] == '_')) {
                            timezoneEndField++;
                        }
                        TimeZone tz =
                                findTimeZone(data, dataStart + dataStringPointer, timezoneEndField - dataStringPointer);
                        if (tz != null) {
                            timezone = tz.getRawOffset();
                        } else {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException("Unexpected timezone string: " + new String(
                                        data, dataStart + dataStringPointer, dataStart + timezoneEndField, ENCODING));
                            } else {
                                return false;
                            }
                        }
                        dataStringPointer = timezoneEndField;
                    }
                    timezoneExists = true;
                    break;
                case AMPM:
                    if (dataStringPointer + 1 < dataLength) {
                        if (hour > 12 || hour <= 0) {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException(
                                        "Hour " + hour + " cannot be a time for AM/PM.");
                            } else {
                                return false;
                            }
                        }
                        if (byteArrayEqualToString(data, dataStart + dataStringPointer, 2, AM_BYTEARRAY)) {
                            // do nothing
                        } else if (byteArrayEqualToString(data, dataStart + dataStringPointer, 2, PM_BYTEARRAY)) {
                            hour += 12;
                            if (hour == 24) {
                                hour = 0;
                            }
                        } else {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException("Unexpected string for AM/PM marker "
                                        + new String(data, dataStart + dataStringPointer,
                                                dataStart + dataStringPointer + 2, ENCODING));
                            } else {
                                return false;
                            }
                        }
                        dataStringPointer += 2;
                    } else {
                        if (raiseParseDataError) {
                            throw new AsterixTemporalTypeParseException("Cannot find valid AM/PM marker.");
                        } else {
                            return false;
                        }
                    }
                    break;
                case SKIPPER:
                    // just skip all continuous character and numbers
                    while ((data[dataStart + dataStringPointer] >= 'a' && data[dataStart + dataStringPointer] <= 'z')
                            || (data[dataStart + dataStringPointer] >= 'A'
                                    && data[dataStart + dataStringPointer] <= 'Z')
                            || (data[dataStart + dataStringPointer] >= '0'
                                    && data[dataStart + dataStringPointer] <= '9')) {
                        dataStringPointer++;
                    }
                    break;
                case SEPARATOR:
                    for (int i = 0; i < formatCharCopies; i++) {
                        byte b = data[dataStart + dataStringPointer];
                        boolean match =
                                (char) b == separatorChar || (altSeparatorChar != '\0' && (char) b == altSeparatorChar);
                        if (!match) {
                            if (raiseParseDataError) {
                                throw new AsterixTemporalTypeParseException(
                                        "Expecting separator " + separatorChar + " but got " + b);
                            } else {
                                return false;
                            }
                        }
                        lastSeparatorChar = (char) b;
                        dataStringPointer++;
                    }
                    break;
                default:
                    throw new AsterixTemporalTypeParseException(
                            "Unexpected time format information when parsing a date value");
            }
        }

        if (dataStringPointer < dataLength) {
            if (raiseParseDataError) {
                throw new AsterixTemporalTypeParseException(
                        "The given data string is not fully parsed by the given format string");
            } else {
                return false;
            }
        }

        if (formatPointer < formatLength) {
            if (raiseParseDataError) {
                throw new AsterixTemporalTypeParseException(
                        "The given format string is not fully used for the given data string");
            } else {
                return false;
            }
        }

        long chronon;
        if (parseMode == DateTimeParseMode.TIME_ONLY) {
            int minYear = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.YEAR.ordinal()];
            int minMonth = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.MONTH.ordinal()];
            int minDay = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
            if (!CAL.validate(minYear, minMonth, minDay, hour, min, sec, ms)) {
                if (raiseParseDataError) {
                    throw new AsterixTemporalTypeParseException("Invalid time value");
                } else {
                    return false;
                }
            }
            chronon = CAL.getChronon(hour, min, sec, ms);
        } else {
            if (!CAL.validate(year, month, day, hour, min, sec, ms)) {
                if (raiseParseDataError) {
                    throw new AsterixTemporalTypeParseException("Invalid date/time value");
                } else {
                    return false;
                }
            }
            chronon = CAL.getChronon(year, month, day, hour, min, sec, ms);
        }

        if (timezoneExists && adjustChrononByTimezone) {
            if (!CAL.validateTimeZone(timezone)) {
                if (raiseParseDataError) {
                    throw new AsterixTemporalTypeParseException("Invalid time zone");
                } else {
                    return false;
                }
            }
            chronon += timezone;
        }

        outChronon.setValue(chronon);
        if (dateTimeSeparatorOut != null) {
            dateTimeSeparatorOut.setValue(dateTimeSeparatorChar);
        }
        if (outTimeZoneExists != null) {
            outTimeZoneExists.setValue(timezoneExists);
        }
        if (outTimeZone != null) {
            outTimeZone.setValue(timezone);
        }
        return true;
    }