private static double date_parseString()

in rhino/src/main/java/org/mozilla/javascript/NativeDate.java [1149:1355]


    private static double date_parseString(Context cx, String s) {
        double d = parseISOString(cx, s);
        if (!Double.isNaN(d)) {
            return d;
        }

        int year = -1;
        int mon = -1;
        int mday = -1;
        int hour = -1;
        int min = -1;
        int sec = -1;
        char c = 0;
        char si = 0;
        int i = 0;
        int n = -1;
        double tzoffset = -1;
        char prevc = 0;
        int limit = 0;
        boolean seenplusminus = false;

        limit = s.length();
        while (i < limit) {
            c = s.charAt(i);
            i++;
            if (c <= ' ' || c == ',' || c == '-') {
                if (i < limit) {
                    si = s.charAt(i);
                    if (c == '-' && '0' <= si && si <= '9') {
                        prevc = c;
                    }
                }
                continue;
            }
            if (c == '(') {
                /* comments) */
                int depth = 1;
                while (i < limit) {
                    c = s.charAt(i);
                    i++;
                    if (c == '(') depth++;
                    else if (c == ')') if (--depth <= 0) break;
                }
                continue;
            }
            if ('0' <= c && c <= '9') {
                n = c - '0';
                while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
                    n = n * 10 + c - '0';
                    i++;
                }

                /* allow TZA before the year, so
                 * 'Wed Nov 05 21:49:11 GMT-0800 1997'
                 * works */

                /* uses of seenplusminus allow : in TZA, so Java
                 * no-timezone style of GMT+4:30 works
                 */
                if ((prevc == '+' || prevc == '-') /*  && year>=0 */) {
                    /* make ':' case below change tzoffset */
                    seenplusminus = true;

                    /* offset */
                    if (n < 24) n = n * 60; /* EG. "GMT-3" */
                    else n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
                    if (prevc == '+') /* plus means east of GMT */ n = -n;
                    if (tzoffset != 0 && tzoffset != -1) return ScriptRuntime.NaN;
                    tzoffset = n;
                } else if (n >= 70 || (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
                    if (year >= 0) return ScriptRuntime.NaN;
                    else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
                        year = n < 100 ? n + 1900 : n;
                    else return ScriptRuntime.NaN;
                } else if (c == ':') {
                    if (hour < 0) hour = /*byte*/ n;
                    else if (min < 0) min = /*byte*/ n;
                    else return ScriptRuntime.NaN;
                } else if (c == '/') {
                    if (mon < 0) mon = /*byte*/ n - 1;
                    else if (mday < 0) mday = /*byte*/ n;
                    else return ScriptRuntime.NaN;
                } else if (i < limit && c != ',' && c > ' ' && c != '-') {
                    return ScriptRuntime.NaN;
                } else if (seenplusminus && n < 60) {
                    /* handle GMT-3:30 */
                    if (tzoffset < 0) tzoffset -= n;
                    else tzoffset += n;
                } else if (hour >= 0 && min < 0) {
                    min = /*byte*/ n;
                } else if (min >= 0 && sec < 0) {
                    sec = /*byte*/ n;
                } else if (mday < 0) {
                    mday = /*byte*/ n;
                } else {
                    return ScriptRuntime.NaN;
                }
                prevc = 0;
            } else if (c == '/' || c == ':' || c == '+' || c == '-') {
                prevc = c;
            } else {
                int st = i - 1;
                while (i < limit) {
                    c = s.charAt(i);
                    if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) break;
                    i++;
                }
                int letterCount = i - st;
                if (letterCount < 2) return ScriptRuntime.NaN;
                /*
                 * Use ported code from jsdate.c rather than the locale-specific
                 * date-parsing code from Java, to keep js and rhino consistent.
                 * Is this the right strategy?
                 */
                String wtb =
                        "am;pm;"
                                + "monday;tuesday;wednesday;thursday;friday;"
                                + "saturday;sunday;"
                                + "january;february;march;april;may;june;"
                                + "july;august;september;october;november;december;"
                                + "gmt;ut;utc;est;edt;cst;cdt;mst;mdt;pst;pdt;";
                int index = 0;
                for (int wtbOffset = 0; ; ) {
                    int wtbNext = wtb.indexOf(';', wtbOffset);
                    if (wtbNext < 0) return ScriptRuntime.NaN;
                    if (wtb.regionMatches(true, wtbOffset, s, st, letterCount)) break;
                    wtbOffset = wtbNext + 1;
                    ++index;
                }
                if (index < 2) {
                    /*
                     * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
                     * 12:30, instead of blindly adding 12 if PM.
                     */
                    if (hour > 12 || hour < 0) {
                        return ScriptRuntime.NaN;
                    } else if (index == 0) {
                        // AM
                        if (hour == 12) hour = 0;
                    } else {
                        // PM
                        if (hour != 12) hour += 12;
                    }
                } else if ((index -= 2) < 7) {
                    // ignore week days
                } else if ((index -= 7) < 12) {
                    // month
                    if (mon < 0) {
                        mon = index;
                    } else {
                        return ScriptRuntime.NaN;
                    }
                } else {
                    index -= 12;
                    // timezones
                    switch (index) {
                        case 0 /* gmt */:
                            tzoffset = 0;
                            break;
                        case 1 /* ut */:
                            tzoffset = 0;
                            break;
                        case 2 /* utc */:
                            tzoffset = 0;
                            break;
                        case 3 /* est */:
                            tzoffset = 5 * 60;
                            break;
                        case 4 /* edt */:
                            tzoffset = 4 * 60;
                            break;
                        case 5 /* cst */:
                            tzoffset = 6 * 60;
                            break;
                        case 6 /* cdt */:
                            tzoffset = 5 * 60;
                            break;
                        case 7 /* mst */:
                            tzoffset = 7 * 60;
                            break;
                        case 8 /* mdt */:
                            tzoffset = 6 * 60;
                            break;
                        case 9 /* pst */:
                            tzoffset = 8 * 60;
                            break;
                        case 10 /* pdt */:
                            tzoffset = 7 * 60;
                            break;
                        default:
                            Kit.codeBug();
                    }
                }
            }
        }
        if (year < 0 || mon < 0 || mday < 0) return ScriptRuntime.NaN;
        if (sec < 0) sec = 0;
        if (min < 0) min = 0;
        if (hour < 0) hour = 0;

        double msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
        if (tzoffset == -1) {
            /* no time zone specified, have to use local */
            return internalUTC(cx, msec);
        }
        return msec + tzoffset * msPerMinute;
    }