static int s_parse_iso_8601()

in source/date_time.c [315:433]


static int s_parse_iso_8601(const struct aws_byte_cursor *date_str_cursor, struct tm *parsed_time) {
    size_t index = 0;
    size_t state_start_index = 0;
    enum parser_state state = ON_YEAR;
    bool error = false;
    bool advance = true;

    AWS_ZERO_STRUCT(*parsed_time);

    while (state < FINISHED && !error && index < date_str_cursor->len) {
        char c = date_str_cursor->ptr[index];
        switch (state) {
            case ON_YEAR:
                if (c == '-' && index - state_start_index == 4) {
                    state = ON_MONTH;
                    state_start_index = index + 1;
                    parsed_time->tm_year -= 1900;
                } else if (aws_isdigit(c)) {
                    parsed_time->tm_year = parsed_time->tm_year * 10 + (c - '0');
                } else {
                    error = true;
                }
                break;
            case ON_MONTH:
                if (c == '-' && index - state_start_index == 2) {
                    state = ON_MONTH_DAY;
                    state_start_index = index + 1;
                    parsed_time->tm_mon -= 1;
                } else if (aws_isdigit(c)) {
                    parsed_time->tm_mon = parsed_time->tm_mon * 10 + (c - '0');
                } else {
                    error = true;
                }

                break;
            case ON_MONTH_DAY:
                if (c == 'T' && index - state_start_index == 2) {
                    state = ON_HOUR;
                    state_start_index = index + 1;
                } else if (aws_isdigit(c)) {
                    parsed_time->tm_mday = parsed_time->tm_mday * 10 + (c - '0');
                } else {
                    error = true;
                }
                break;
            /* note: no time portion is spec compliant. */
            case ON_HOUR:
                /* time parts can be delimited by ':' or just concatenated together, but must always be 2 digits. */
                if (index - state_start_index == 2) {
                    state = ON_MINUTE;
                    state_start_index = index + 1;
                    if (aws_isdigit(c)) {
                        state_start_index = index;
                        advance = false;
                    } else if (c != ':') {
                        error = true;
                    }
                } else if (aws_isdigit(c)) {
                    parsed_time->tm_hour = parsed_time->tm_hour * 10 + (c - '0');
                } else {
                    error = true;
                }

                break;
            case ON_MINUTE:
                /* time parts can be delimited by ':' or just concatenated together, but must always be 2 digits. */
                if (index - state_start_index == 2) {
                    state = ON_SECOND;
                    state_start_index = index + 1;
                    if (aws_isdigit(c)) {
                        state_start_index = index;
                        advance = false;
                    } else if (c != ':') {
                        error = true;
                    }
                } else if (aws_isdigit(c)) {
                    parsed_time->tm_min = parsed_time->tm_min * 10 + (c - '0');
                } else {
                    error = true;
                }

                break;
            case ON_SECOND:
                if (c == 'Z' && index - state_start_index == 2) {
                    state = FINISHED;
                    state_start_index = index + 1;
                } else if (c == '.' && index - state_start_index == 2) {
                    state = ON_TZ;
                    state_start_index = index + 1;
                } else if (aws_isdigit(c)) {
                    parsed_time->tm_sec = parsed_time->tm_sec * 10 + (c - '0');
                } else {
                    error = true;
                }

                break;
            case ON_TZ:
                if (c == 'Z') {
                    state = FINISHED;
                    state_start_index = index + 1;
                } else if (!aws_isdigit(c)) {
                    error = true;
                }
                break;
            default:
                error = true;
                break;
        }

        if (advance) {
            index++;
        } else {
            advance = true;
        }
    }

    /* ISO8601 supports date only with no time portion. state ==ON_MONTH_DAY catches this case. */
    return (state == FINISHED || state == ON_MONTH_DAY) && !error ? AWS_OP_SUCCESS : AWS_OP_ERR;
}