private static double parseISOString(String s) {
        // we use a simple state machine to parse the input string
        final int ERROR = -1;
        final int YEAR = 0, MONTH = 1, DAY = 2;
        final int HOUR = 3, MIN = 4, SEC = 5, MSEC = 6;
        final int TZHOUR = 7, TZMIN = 8;
        int state = YEAR;
        // default values per [15.9.1.15 Date Time String Format]
        int[] values = { 1970, 1, 1, 0, 0, 0, 0, -1, -1 };
        int yearlen = 4, yearmod = 1, tzmod = 1;
        int i = 0, len = s.length();
        if (len != 0) {
            char c = s.charAt(0);
            if (c == '+' || c == '-') {
                // 15.9.1.15.1 Extended years
                i += 1;
                yearlen = 6;
                yearmod = (c == '-') ? -1 : 1;
            } else if (c == 'T') {
                // time-only forms no longer in spec, but follow spidermonkey here
                i += 1;
                state = HOUR;
            }
        }
        loop: while (state != ERROR) {
            int m = i + (state == YEAR ? yearlen : state == MSEC ? 3 : 2);
            if (m > len) {
                state = ERROR;
                break;
            }

            int value = 0;
            for (; i < m; ++i) {
                char c = s.charAt(i);
                if (c < '0' || c > '9') { state = ERROR; break loop; }
                value = 10 * value + (c - '0');
            }
            values[state] = value;

            if (i == len) {
                // reached EOF, check for end state
                switch (state) {
                case HOUR:
                case TZHOUR:
                    state = ERROR;
                }
                break;
            }

            char c = s.charAt(i++);
            if (c == 'Z') {
                // handle abbrevation for UTC timezone
                values[TZHOUR] = 0;
                values[TZMIN] = 0;
                switch (state) {
                case MIN:
                case SEC:
                case MSEC:
                    break;
                default:
                    state = ERROR;
                }
                break;
            }

            // state transition
            switch (state) {
            case YEAR:
            case MONTH:
                state = (c == '-' ? state + 1 : c == 'T' ? HOUR : ERROR);
                break;
            case DAY:
                state = (c == 'T' ? HOUR : ERROR);
                break;
            case HOUR:
                state = (c == ':' ? MIN : ERROR);
                break;
            case TZHOUR:
                // state = (c == ':' ? state + 1 : ERROR);
                // Non-standard extension, https://bugzilla.mozilla.org/show_bug.cgi?id=682754
                if (c != ':') {
                    // back off by one and try to read without ':' separator
                    i -= 1;
                }
                state = TZMIN;
                break;
            case MIN:
                state = (c == ':' ? SEC : c == '+' || c == '-' ? TZHOUR : ERROR);
                break;
            case SEC:
                state = (c == '.' ? MSEC : c == '+' || c == '-' ? TZHOUR : ERROR);
                break;
            case MSEC:
                state = (c == '+' || c == '-' ? TZHOUR : ERROR);
                break;
            case TZMIN:
                state = ERROR;
                break;
            }
            if (state == TZHOUR) {
                // save timezone modificator
                tzmod = (c == '-') ? -1 : 1;
            }
        }

        syntax: {
            // error or unparsed characters
            if (state == ERROR || i != len) break syntax;

            // check values
            int year = values[YEAR], month = values[MONTH], day = values[DAY];
            int hour = values[HOUR], min = values[MIN], sec = values[SEC], msec = values[MSEC];
            int tzhour = values[TZHOUR], tzmin = values[TZMIN];
            if (year > 275943 // ceil(1e8/365) + 1970 = 275943
                || (month < 1 || month > 12)
                || (day < 1 || day > DaysInMonth(year, month))
                || hour > 24
                || (hour == 24 && (min > 0 || sec > 0 || msec > 0))
                || min > 59
                || sec > 59
                || tzhour > 23
                || tzmin > 59
               ) {
                break syntax;
            }
            // valid ISO-8601 format, compute date in milliseconds
            double date = date_msecFromDate(year * yearmod, month - 1, day,
                                            hour, min, sec, msec);
            if (tzhour == -1) {
                // Spec says to use UTC timezone, the following bug report says
                // that local timezone was meant to be used. Stick with spec for now.
                // https://bugs.ecmascript.org/show_bug.cgi?id=112
                // date = internalUTC(date);
            } else {
                date -= (tzhour * 60 + tzmin) * msPerMinute * tzmod;
            }

            if (date < -HalfTimeDomain || date > HalfTimeDomain) break syntax;
            return date;
        }

        // invalid ISO-8601 format, return NaN
        return ScriptRuntime.NaN;
    }
private static double parseISOString ( String s ) { final int ERROR = - 1 ; final int YEAR = 0 , MONTH = 1 , DAY = 2 ; final int HOUR = 3 , MIN = 4 , SEC = 5 , MSEC = 6 ; final int TZHOUR = 7 , TZMIN = 8 ; int state = YEAR ; int [ ] values = { 1970 , 1 , 1 , 0 , 0 , 0 , 0 , - 1 , - 1 } ; int yearlen = 4 , yearmod = 1 , tzmod = 1 ; int i = 0 , len = s . length ( ) ; if ( len != 0 ) { char c = s . charAt ( 0 ) ; if ( c == '+' || c == '-' ) { i += 1 ; yearlen = 6 ; yearmod = ( c == '-' ) ? - 1 : 1 ; } else if ( c == 'T' ) { i += 1 ; state = HOUR ; } } loop : while ( state != ERROR ) { int m = i + ( state == YEAR ? yearlen : state == MSEC ? 3 : 2 ) ; if ( m > len ) { state = ERROR ; break ; } int value = 0 ; for ( ; i < m ; ++ i ) { char c = s . charAt ( i ) ; if ( c < '0' || c > '9' ) { state = ERROR ; break loop ; } value = 10 * value + ( c - '0' ) ; } values [ state ] = value ; if ( i == len ) { switch ( state ) { case HOUR : case TZHOUR : state = ERROR ; } break ; } char c = s . charAt ( i ++ ) ; if ( c == 'Z' ) { values [ TZHOUR ] = 0 ; values [ TZMIN ] = 0 ; switch ( state ) { case MIN : case SEC : case MSEC : break ; default : state = ERROR ; } break ; } switch ( state ) { case YEAR : case MONTH : state = ( c == '-' ? state + 1 : c == 'T' ? HOUR : ERROR ) ; break ; case DAY : state = ( c == 'T' ? HOUR : ERROR ) ; break ; case HOUR : state = ( c == ':' ? MIN : ERROR ) ; break ; case TZHOUR : if ( c != ':' ) { i -= 1 ; } state = TZMIN ; break ; case MIN : state = ( c == ':' ? SEC : c == '+' || c == '-' ? TZHOUR : ERROR ) ; break ; case SEC : state = ( c == '.' ? MSEC : c == '+' || c == '-' ? TZHOUR : ERROR ) ; break ; case MSEC : state = ( c == '+' || c == '-' ? TZHOUR : ERROR ) ; break ; case TZMIN : state = ERROR ; break ; } if ( state == TZHOUR ) { tzmod = ( c == '-' ) ? - 1 : 1 ; } } syntax : { if ( state == ERROR || i != len ) break syntax ; int year = values [ YEAR ] , month = values [ MONTH ] , day = values [ DAY ] ; int hour = values [ HOUR ] , min = values [ MIN ] , sec = values [ SEC ] , msec = values [ MSEC ] ; int tzhour = values [ TZHOUR ] , tzmin = values [ TZMIN ] ; if ( year > 275943 || ( month < 1 || month > 12 ) || ( day < 1 || day > DaysInMonth ( year , month ) ) || hour > 24 || ( hour == 24 && ( min > 0 || sec > 0 || msec > 0 ) ) || min > 59 || sec > 59 || tzhour > 23 || tzmin > 59 ) { break syntax ; } double date = date_msecFromDate ( year * yearmod , month - 1 , day , hour , min , sec , msec ) ; if ( tzhour == - 1 ) { } else { date -= ( tzhour * 60 + tzmin ) * msPerMinute * tzmod ; } if ( date < - HalfTimeDomain || date > HalfTimeDomain ) break syntax ; return date ; } return ScriptRuntime . NaN ; }
15.9.1.15 Date Time String Format<br>
Parse input string according to simplified ISO-8601 Extended Format:
<ul>
<li><code>YYYY-MM-DD'T'HH:mm:ss.sss'Z'</code></li>
<li>or <code>YYYY-MM-DD'T'HH:mm:ss.sss[+-]hh:mm</code></li>
</ul>