[re]-merged in Brians stuff
[org.ibex.core.git] / src / org / ibex / js / JSDate.java
diff --git a/src/org/ibex/js/JSDate.java b/src/org/ibex/js/JSDate.java
deleted file mode 100644 (file)
index 144e868..0000000
+++ /dev/null
@@ -1,1247 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * The contents of this file are subject to the Netscape Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/NPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation.  Portions created by Netscape are
- * Copyright (C) 1997-1999 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- * Norris Boyd
- * Mike McCabe
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License (the "GPL"), in which case the
- * provisions of the GPL are applicable instead of those above.
- * If you wish to allow use of your version of this file only
- * under the terms of the GPL and not to allow others to use your
- * version of this file under the NPL, indicate your decision by
- * deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL.  If you do not delete
- * the provisions above, a recipient may use your version of this
- * file under either the NPL or the GPL.
- */
-
-package org.ibex.js;
-
-import java.text.DateFormat;
-
-/**
- * This class implements the Date native object.
- * See ECMA 15.9.
- * @author Mike McCabe
- * @author Adam Megacz (many modifications
- */
-public class JSDate extends JS {
-
-    public JSDate() {
-        if (thisTimeZone == null) {
-            // j.u.TimeZone is synchronized, so setting class statics from it
-            // should be OK.
-            thisTimeZone = java.util.TimeZone.getDefault();
-            LocalTZA = thisTimeZone.getRawOffset();
-        }
-    }
-
-    String coerceToString() { return date_format(date, FORMATSPEC_FULL); }
-
-    public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
-        switch(nargs) {
-            case 0: {
-                //#jswitch(method)
-                case "toString": return JS.S(date_format(date, FORMATSPEC_FULL));
-                case "toTimeString": return JS.S(date_format(date, FORMATSPEC_TIME));
-                case "toDateString": return JS.S(date_format(date, FORMATSPEC_DATE));
-                case "toLocaleString": return JS.S(toLocaleString(date));
-                case "toLocaleTimeString": return JS.S(toLocaleTimeString(date));
-                case "toLocaleDateString": return JS.S(toLocaleDateString(date));
-                case "toUTCString": return JS.S(toUTCString(date));
-                case "valueOf": return N(this.date);
-                case "getTime": return N(this.date);
-                case "getYear": return N(getYear(date));
-                case "getFullYear": return N(YearFromTime(LocalTime(date)));
-                case "getUTCFullYear": return N(YearFromTime(date));
-                case "getMonth": return N(MonthFromTime(LocalTime(date)));
-                case "getUTCMonth": return N(MonthFromTime(date));
-                case "getDate": return N(DateFromTime(LocalTime(date)));
-                case "getUTCDate": return N(DateFromTime(date));
-                case "getDay": return N(WeekDay(LocalTime(date)));
-                case "getUTCDay": return N(WeekDay(date));
-                case "getHours": return N(HourFromTime(LocalTime(date)));
-                case "getUTCHours": return N(HourFromTime(date));
-                case "getMinutes": return N(MinFromTime(LocalTime(date)));
-                case "getUTCMinutes": return N(MinFromTime(date));
-                case "getSeconds": return N(SecFromTime(LocalTime(date)));
-                case "getUTCSeconds": return N(SecFromTime(date));
-                case "getMilliseconds": return N(msFromTime(LocalTime(date)));
-                case "getUTCMilliseconds": return N(msFromTime(date));
-                case "getTimezoneOffset": return N(getTimezoneOffset(date));
-                //#end
-                return super.callMethod(method, a0, a1, a2, rest, nargs);
-            }
-            case 1: {
-                //#jswitch(method)
-                case "setTime": return N(this.setTime(toDouble(a0)));
-                case "setYear": return N(this.setYear(toDouble(a0)));
-                //#end
-                // fall through
-            }
-            default: {
-                JS[] args = new JS[nargs];
-                for(int i=0; i<nargs; i++) args[i] = i==0 ? a0 : i==1 ? a1 : i==2 ? a2 : rest[i-3];
-                //#jswitch(method)
-                case "setMilliseconds": return N(this.makeTime(args, 1, true));
-                case "setUTCMilliseconds": return N(this.makeTime(args, 1, false));
-                case "setSeconds": return N(this.makeTime(args, 2, true));
-                case "setUTCSeconds": return N(this.makeTime(args, 2, false));
-                case "setMinutes": return N(this.makeTime(args, 3, true));
-                case "setUTCMinutes": return N(this.makeTime(args, 3, false));
-                case "setHours": return N(this.makeTime(args, 4, true));
-                case "setUTCHours": return N(this.makeTime(args, 4, false));
-                case "setDate": return N(this.makeDate(args, 1, true));
-                case "setUTCDate": return N(this.makeDate(args, 1, false));
-                case "setMonth": return N(this.makeDate(args, 2, true));
-                case "setUTCMonth": return N(this.makeDate(args, 2, false));
-                case "setFullYear": return N(this.makeDate(args, 3, true));
-                case "setUTCFullYear": return N(this.makeDate(args, 3, false));
-                //#end
-            }
-        }
-        return super.callMethod(method, a0, a1, a2, rest, nargs);
-    }
-
-    public JS get(JS key) throws JSExn {
-        //#jswitch(key)
-        case "toString": return METHOD;
-        case "toTimeString": return METHOD;
-        case "toDateString": return METHOD;
-        case "toLocaleString": return METHOD;
-        case "toLocaleTimeString": return METHOD;
-        case "toLocaleDateString": return METHOD;
-        case "toUTCString": return METHOD;
-        case "valueOf": return METHOD;
-        case "getTime": return METHOD;
-        case "getYear": return METHOD;
-        case "getFullYear": return METHOD;
-        case "getUTCFullYear": return METHOD;
-        case "getMonth": return METHOD;
-        case "getUTCMonth": return METHOD;
-        case "getDate": return METHOD;
-        case "getUTCDate": return METHOD;
-        case "getDay": return METHOD;
-        case "getUTCDay": return METHOD;
-        case "getHours": return METHOD;
-        case "getUTCHours": return METHOD;
-        case "getMinutes": return METHOD;
-        case "getUTCMinutes": return METHOD;
-        case "getSeconds": return METHOD;
-        case "getUTCSeconds": return METHOD;
-        case "getMilliseconds": return METHOD;
-        case "getUTCMilliseconds": return METHOD;
-        case "getTimezoneOffset": return METHOD;
-        case "setTime": return METHOD;
-        case "setYear": return METHOD;
-        case "setMilliseconds": return METHOD;
-        case "setUTCMilliseconds": return METHOD;
-        case "setSeconds": return METHOD;
-        case "setUTCSeconds": return METHOD;
-        case "setMinutes": return METHOD;
-        case "setUTCMinutes": return METHOD;
-        case "setHours": return METHOD;
-        case "setUTCHours": return METHOD;
-        case "setDate": return METHOD;
-        case "setUTCDate": return METHOD;
-        case "setMonth": return METHOD;
-        case "setUTCMonth": return METHOD;
-        case "setFullYear": return METHOD;
-        case "setUTCFullYear": return METHOD;
-        //#end
-        return super.get(key);
-    }
-
-    /* ECMA helper functions */
-
-    private static final double HalfTimeDomain = 8.64e15;
-    private static final double HoursPerDay    = 24.0;
-    private static final double MinutesPerHour = 60.0;
-    private static final double SecondsPerMinute = 60.0;
-    private static final double msPerSecond    = 1000.0;
-    private static final double MinutesPerDay  = (HoursPerDay * MinutesPerHour);
-    private static final double SecondsPerDay  = (MinutesPerDay * SecondsPerMinute);
-    private static final double SecondsPerHour = (MinutesPerHour * SecondsPerMinute);
-    private static final double msPerDay       = (SecondsPerDay * msPerSecond);
-    private static final double msPerHour      = (SecondsPerHour * msPerSecond);
-    private static final double msPerMinute    = (SecondsPerMinute * msPerSecond);
-
-    private static double Day(double t) {
-        return java.lang.Math.floor(t / msPerDay);
-    }
-
-    private static double TimeWithinDay(double t) {
-        double result;
-        result = t % msPerDay;
-        if (result < 0)
-            result += msPerDay;
-        return result;
-    }
-
-    private static int DaysInYear(int y) {
-        if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
-            return 366;
-        else
-            return 365;
-    }
-
-
-    /* math here has to be f.p, because we need
-     *  floor((1968 - 1969) / 4) == -1
-     */
-    private static double DayFromYear(double y) {
-        return ((365 * ((y)-1970) + java.lang.Math.floor(((y)-1969)/4.0)
-                 - java.lang.Math.floor(((y)-1901)/100.0) + java.lang.Math.floor(((y)-1601)/400.0)));
-    }
-
-    private static double TimeFromYear(double y) {
-        return DayFromYear(y) * msPerDay;
-    }
-
-    private static int YearFromTime(double t) {
-        int lo = (int) java.lang.Math.floor((t / msPerDay) / 366) + 1970;
-        int hi = (int) java.lang.Math.floor((t / msPerDay) / 365) + 1970;
-        int mid;
-
-        /* above doesn't work for negative dates... */
-        if (hi < lo) {
-            int temp = lo;
-            lo = hi;
-            hi = temp;
-        }
-
-        /* Use a simple binary search algorithm to find the right
-           year.  This seems like brute force... but the computation
-           of hi and lo years above lands within one year of the
-           correct answer for years within a thousand years of
-           1970; the loop below only requires six iterations
-           for year 270000. */
-        while (hi > lo) {
-            mid = (hi + lo) / 2;
-            if (TimeFromYear(mid) > t) {
-                hi = mid - 1;
-            } else {
-                if (TimeFromYear(mid) <= t) {
-                    int temp = mid + 1;
-                    if (TimeFromYear(temp) > t) {
-                        return mid;
-                    }
-                    lo = mid + 1;
-                }
-            }
-        }
-        return lo;
-    }
-
-    private static boolean InLeapYear(double t) {
-        return DaysInYear(YearFromTime(t)) == 366;
-    }
-
-    private static int DayWithinYear(double t) {
-        int year = YearFromTime(t);
-        return (int) (Day(t) - DayFromYear(year));
-    }
-    /*
-     * The following array contains the day of year for the first day of
-     * each month, where index 0 is January, and day 0 is January 1.
-     */
-
-    private static double DayFromMonth(int m, boolean leap) {
-        int day = m * 30;
-
-        if (m >= 7) { day += m / 2 - 1; }
-        else if (m >= 2) { day += (m - 1) / 2 - 1; }
-        else { day += m; }
-
-        if (leap && m >= 2) { ++day; }
-
-        return day;
-    }
-
-    private static int MonthFromTime(double t) {
-        int d, step;
-
-        d = DayWithinYear(t);
-
-        if (d < (step = 31))
-            return 0;
-
-        // Originally coded as step += (InLeapYear(t) ? 29 : 28);
-        // but some jits always returned 28!
-        if (InLeapYear(t))
-            step += 29;
-        else
-            step += 28;
-
-        if (d < step)
-            return 1;
-        if (d < (step += 31))
-            return 2;
-        if (d < (step += 30))
-            return 3;
-        if (d < (step += 31))
-            return 4;
-        if (d < (step += 30))
-            return 5;
-        if (d < (step += 31))
-            return 6;
-        if (d < (step += 31))
-            return 7;
-        if (d < (step += 30))
-            return 8;
-        if (d < (step += 31))
-            return 9;
-        if (d < (step += 30))
-            return 10;
-        return 11;
-    }
-
-    private static int DateFromTime(double t) {
-        int d, step, next;
-
-        d = DayWithinYear(t);
-        if (d <= (next = 30))
-            return d + 1;
-        step = next;
-
-        // Originally coded as next += (InLeapYear(t) ? 29 : 28);
-        // but some jits always returned 28!
-        if (InLeapYear(t))
-            next += 29;
-        else
-            next += 28;
-
-        if (d <= next)
-            return d - step;
-        step = next;
-        if (d <= (next += 31))
-            return d - step;
-        step = next;
-        if (d <= (next += 30))
-            return d - step;
-        step = next;
-        if (d <= (next += 31))
-            return d - step;
-        step = next;
-        if (d <= (next += 30))
-            return d - step;
-        step = next;
-        if (d <= (next += 31))
-            return d - step;
-        step = next;
-        if (d <= (next += 31))
-            return d - step;
-        step = next;
-        if (d <= (next += 30))
-            return d - step;
-        step = next;
-        if (d <= (next += 31))
-            return d - step;
-        step = next;
-        if (d <= (next += 30))
-            return d - step;
-        step = next;
-
-        return d - step;
-    }
-
-    private static int WeekDay(double t) {
-        double result;
-        result = Day(t) + 4;
-        result = result % 7;
-        if (result < 0)
-            result += 7;
-        return (int) result;
-    }
-
-    private static double Now() {
-        return (double) System.currentTimeMillis();
-    }
-
-    /* Should be possible to determine the need for this dynamically
-     * if we go with the workaround... I'm not using it now, because I
-     * can't think of any clean way to make toLocaleString() and the
-     * time zone (comment) in toString match the generated string
-     * values.  Currently it's wrong-but-consistent in all but the
-     * most recent betas of the JRE - seems to work in 1.1.7.
-     */
-    private final static boolean TZO_WORKAROUND = false;
-    private static double DaylightSavingTA(double t) {
-        if (!TZO_WORKAROUND) {
-            java.util.Date date = new java.util.Date((long) t);
-            if (thisTimeZone.inDaylightTime(date))
-                return msPerHour;
-            else
-                return 0;
-        } else {
-            /* Use getOffset if inDaylightTime() is broken, because it
-             * seems to work acceptably.  We don't switch over to it
-             * entirely, because it requires (expensive) exploded date arguments,
-             * and the api makes it impossible to handle dst
-             * changeovers cleanly.
-             */
-
-            // Hardcode the assumption that the changeover always
-            // happens at 2:00 AM:
-            t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);
-
-            int year = YearFromTime(t);
-            double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0,
-                                                   year,
-                                                   MonthFromTime(t),
-                                                   DateFromTime(t),
-                                                   WeekDay(t),
-                                                   (int)TimeWithinDay(t));
-
-            if ((offset - LocalTZA) != 0)
-                return msPerHour;
-            else
-                return 0;
-            //         return offset - LocalTZA;
-        }
-    }
-
-    private static double LocalTime(double t) {
-        return t + LocalTZA + DaylightSavingTA(t);
-    }
-
-    public static double internalUTC(double t) {
-        return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
-    }
-
-    private static int HourFromTime(double t) {
-        double result;
-        result = java.lang.Math.floor(t / msPerHour) % HoursPerDay;
-        if (result < 0)
-            result += HoursPerDay;
-        return (int) result;
-    }
-
-    private static int MinFromTime(double t) {
-        double result;
-        result = java.lang.Math.floor(t / msPerMinute) % MinutesPerHour;
-        if (result < 0)
-            result += MinutesPerHour;
-        return (int) result;
-    }
-
-    private static int SecFromTime(double t) {
-        double result;
-        result = java.lang.Math.floor(t / msPerSecond) % SecondsPerMinute;
-        if (result < 0)
-            result += SecondsPerMinute;
-        return (int) result;
-    }
-
-    private static int msFromTime(double t) {
-        double result;
-        result =  t % msPerSecond;
-        if (result < 0)
-            result += msPerSecond;
-        return (int) result;
-    }
-
-    private static double MakeTime(double hour, double min,
-                                   double sec, double ms)
-    {
-        return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)
-            * msPerSecond + ms;
-    }
-
-    private static double MakeDay(double year, double month, double date) {
-        double result;
-        boolean leap;
-        double yearday;
-        double monthday;
-
-        year += java.lang.Math.floor(month / 12);
-
-        month = month % 12;
-        if (month < 0)
-            month += 12;
-
-        leap = (DaysInYear((int) year) == 366);
-
-        yearday = java.lang.Math.floor(TimeFromYear(year) / msPerDay);
-        monthday = DayFromMonth((int) month, leap);
-
-        result = yearday
-            + monthday
-            + date - 1;
-        return result;
-    }
-
-    private static double MakeDate(double day, double time) {
-        return day * msPerDay + time;
-    }
-
-    private static double TimeClip(double d) {
-        if (d != d ||
-            d == Double.POSITIVE_INFINITY ||
-            d == Double.NEGATIVE_INFINITY ||
-            java.lang.Math.abs(d) > HalfTimeDomain)
-        {
-            return Double.NaN;
-        }
-        if (d > 0.0)
-            return java.lang.Math.floor(d + 0.);
-        else
-            return java.lang.Math.ceil(d + 0.);
-    }
-
-    /* end of ECMA helper functions */
-
-    /* find UTC time from given date... no 1900 correction! */
-    public static double date_msecFromDate(double year, double mon,
-                                            double mday, double hour,
-                                            double min, double sec,
-                                            double msec)
-    {
-        double day;
-        double time;
-        double result;
-
-        day = MakeDay(year, mon, mday);
-        time = MakeTime(hour, min, sec, msec);
-        result = MakeDate(day, time);
-        return result;
-    }
-
-
-    private static final int MAXARGS = 7;
-    private static double jsStaticJSFunction_UTC(JS[] args) throws JSExn {
-        double array[] = new double[MAXARGS];
-        int loop;
-        double d;
-
-        for (loop = 0; loop < MAXARGS; loop++) {
-            if (loop < args.length) {
-                d = _toNumber(args[loop]);
-                if (d != d || Double.isInfinite(d)) {
-                    return Double.NaN;
-                }
-                array[loop] = toDouble(args[loop]);
-            } else {
-                array[loop] = 0;
-            }
-        }
-
-        /* adjust 2-digit years into the 20th century */
-        if (array[0] >= 0 && array[0] <= 99)
-            array[0] += 1900;
-
-            /* if we got a 0 for 'date' (which is out of range)
-             * pretend it's a 1.  (So Date.UTC(1972, 5) works) */
-        if (array[2] < 1)
-            array[2] = 1;
-
-        d = date_msecFromDate(array[0], array[1], array[2],
-                              array[3], array[4], array[5], array[6]);
-        d = TimeClip(d);
-        return d;
-        //        return N(d);
-    }
-
-    /*
-     * 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?
-     */
-
-    /* for use by date_parse */
-
-    /* replace this with byte arrays?  Cheaper? */
-    private static 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"
-        /* time zone table needs to be expanded */
-    };
-
-    private static int ttb[] = {
-        -1, -2, 0, 0, 0, 0, 0, 0, 0,     /* AM/PM */
-        2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
-        10000 + 0, 10000 + 0, 10000 + 0, /* UT/UTC */
-        10000 + 5 * 60, 10000 + 4 * 60,  /* EDT */
-        10000 + 6 * 60, 10000 + 5 * 60,
-        10000 + 7 * 60, 10000 + 6 * 60,
-        10000 + 8 * 60, 10000 + 7 * 60
-    };
-
-    /* helper for date_parse */
-    private static boolean date_regionMatches(String s1, int s1off,
-                                              String s2, int s2off,
-                                              int count)
-    {
-        boolean result = false;
-        /* return true if matches, otherwise, false */
-        int s1len = s1.length();
-        int s2len = s2.length();
-
-        while (count > 0 && s1off < s1len && s2off < s2len) {
-            if (Character.toLowerCase(s1.charAt(s1off)) !=
-                Character.toLowerCase(s2.charAt(s2off)))
-                break;
-            s1off++;
-            s2off++;
-            count--;
-        }
-
-        if (count == 0) {
-            result = true;
-        }
-        return result;
-    }
-
-    private static double date_parseString(String s) {
-        double msec;
-
-        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;
-
-        if (s == null)  // ??? Will s be null?
-            return Double.NaN;
-        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 Double.NaN;
-                    tzoffset = n;
-                } else if (n >= 70  ||
-                           (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
-                    if (year >= 0)
-                        return Double.NaN;
-                    else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
-                        year = n < 100 ? n + 1900 : n;
-                    else
-                        return Double.NaN;
-                } else if (c == ':') {
-                    if (hour < 0)
-                        hour = /*byte*/ n;
-                    else if (min < 0)
-                        min = /*byte*/ n;
-                    else
-                        return Double.NaN;
-                } else if (c == '/') {
-                    if (mon < 0)
-                        mon = /*byte*/ n-1;
-                    else if (mday < 0)
-                        mday = /*byte*/ n;
-                    else
-                        return Double.NaN;
-                } else if (i < limit && c != ',' && c > ' ' && c != '-') {
-                    return Double.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 Double.NaN;
-                }
-                prevc = 0;
-            } else if (c == '/' || c == ':' || c == '+' || c == '-') {
-                prevc = c;
-            } else {
-                int st = i - 1;
-                int k;
-                while (i < limit) {
-                    c = s.charAt(i);
-                    if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
-                        break;
-                    i++;
-                }
-                if (i <= st + 1)
-                    return Double.NaN;
-                for (k = wtb.length; --k >= 0;)
-                    if (date_regionMatches(wtb[k], 0, s, st, i-st)) {
-                        int action = ttb[k];
-                        if (action != 0) {
-                            if (action < 0) {
-                                /*
-                                 * 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 Double.NaN;
-                                } else {
-                                    if (action == -1 && hour == 12) { // am
-                                        hour = 0;
-                                    } else if (action == -2 && hour != 12) {// pm
-                                        hour += 12;
-                                    }
-                                }
-                            } else if (action <= 13) { /* month! */
-                                if (mon < 0) {
-                                    mon = /*byte*/ (action - 2);
-                                } else {
-                                    return Double.NaN;
-                                }
-                            } else {
-                                tzoffset = action - 10000;
-                            }
-                        }
-                        break;
-                    }
-                if (k < 0)
-                    return Double.NaN;
-                prevc = 0;
-            }
-        }
-        if (year < 0 || mon < 0 || mday < 0)
-            return Double.NaN;
-        if (sec < 0)
-            sec = 0;
-        if (min < 0)
-            min = 0;
-        if (hour < 0)
-            hour = 0;
-        if (tzoffset == -1) { /* no time zone specified, have to use local */
-            double time;
-            time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
-            return internalUTC(time);
-        }
-
-        msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
-        msec += tzoffset * msPerMinute;
-        return msec;
-    }
-
-    private static double jsStaticJSFunction_parse(String s) {
-        return date_parseString(s);
-    }
-
-    private static final int FORMATSPEC_FULL = 0;
-    private static final int FORMATSPEC_DATE = 1;
-    private static final int FORMATSPEC_TIME = 2;
-
-    private static String date_format(double t, int format) {
-        if (t != t)
-            return NaN_date_str;
-
-        StringBuffer result = new StringBuffer(60);
-        double local = LocalTime(t);
-
-        /* offset from GMT in minutes.  The offset includes daylight savings,
-           if it applies. */
-        int minutes = (int) java.lang.Math.floor((LocalTZA + DaylightSavingTA(t))
-                                       / msPerMinute);
-        /* map 510 minutes to 0830 hours */
-        int offset = (minutes / 60) * 100 + minutes % 60;
-
-        String dateStr = Integer.toString(DateFromTime(local));
-        String hourStr = Integer.toString(HourFromTime(local));
-        String minStr = Integer.toString(MinFromTime(local));
-        String secStr = Integer.toString(SecFromTime(local));
-        String offsetStr = Integer.toString(offset > 0 ? offset : -offset);
-        int year = YearFromTime(local);
-        String yearStr = Integer.toString(year > 0 ? year : -year);
-
-        /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
-        /* Tue Oct 31 2000 */
-        /* 09:41:40 GMT-0800 (PST) */
-
-        if (format != FORMATSPEC_TIME) {
-            result.append(days[WeekDay(local)]);
-            result.append(' ');
-            result.append(months[MonthFromTime(local)]);
-            if (dateStr.length() == 1)
-                result.append(" 0");
-            else
-                result.append(' ');
-            result.append(dateStr);
-            result.append(' ');
-        }
-
-        if (format != FORMATSPEC_DATE) {
-            if (hourStr.length() == 1)
-                result.append('0');
-            result.append(hourStr);
-            if (minStr.length() == 1)
-                result.append(":0");
-            else
-                result.append(':');
-            result.append(minStr);
-            if (secStr.length() == 1)
-                result.append(":0");
-            else
-                result.append(':');
-            result.append(secStr);
-            if (offset > 0)
-                result.append(" GMT+");
-            else
-                result.append(" GMT-");
-            for (int i = offsetStr.length(); i < 4; i++)
-                result.append('0');
-            result.append(offsetStr);
-
-            if (timeZoneFormatter == null)
-                timeZoneFormatter = new java.text.SimpleDateFormat("zzz");
-
-            if (timeZoneFormatter != null) {
-                result.append(" (");
-                java.util.Date date = new java.util.Date((long) t);
-                result.append(timeZoneFormatter.format(date));
-                result.append(')');
-            }
-            if (format != FORMATSPEC_TIME)
-                result.append(' ');
-        }
-
-        if (format != FORMATSPEC_TIME) {
-            if (year < 0)
-                result.append('-');
-            for (int i = yearStr.length(); i < 4; i++)
-                result.append('0');
-            result.append(yearStr);
-        }
-
-        return result.toString();
-    }
-
-    private static double _toNumber(JS o) throws JSExn { return JS.toDouble(o); }
-    private static double _toNumber(JS[] o, int index) throws JSExn { return JS.toDouble(o[index]); }
-    private static double toDouble(double d) { return d; }
-
-    public JSDate(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
-
-        JSDate obj = this;
-        switch (nargs) {
-            case 0: {
-                obj.date = Now();
-                return;
-            }
-            case 1: {
-                double date;
-                if(isString(a0))
-                    date = date_parseString(JS.toString(a0));
-                else
-                    date = _toNumber(a0);
-                obj.date = TimeClip(date);
-                return;
-            }
-            default: {
-                // multiple arguments; year, month, day etc.
-                double array[] = new double[MAXARGS];
-                array[0] = toDouble(a0);
-                array[1] = toDouble(a1);
-                if (nargs >= 2) array[2] = toDouble(a2);
-                for(int i=0; i<nargs; i++) {
-                    double d = _toNumber(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
-                    if (d != d || Double.isInfinite(d)) {
-                        obj.date = Double.NaN;
-                        return;
-                    }
-                    array[i] = d;
-                }
-                
-                /* adjust 2-digit years into the 20th century */
-                if (array[0] >= 0 && array[0] <= 99)
-                    array[0] += 1900;
-                
-                /* if we got a 0 for 'date' (which is out of range)
-                 * pretend it's a 1 */
-                if (array[2] < 1)
-                    array[2] = 1;
-                
-                double day = MakeDay(array[0], array[1], array[2]);
-                double time = MakeTime(array[3], array[4], array[5], array[6]);
-                time = MakeDate(day, time);
-                time = internalUTC(time);
-                obj.date = TimeClip(time);
-                
-                return;
-            }
-        }
-    }
-
-    /* constants for toString, toUTCString */
-    private static String NaN_date_str = "Invalid Date";
-
-    private static String[] days = {
-        "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
-    };
-
-    private static String[] months = {
-        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-    };
-
-    private static String toLocale_helper(double t,
-                                          java.text.DateFormat formatter)
-    {
-        if (t != t)
-            return NaN_date_str;
-
-        java.util.Date tempdate = new java.util.Date((long) t);
-        return formatter.format(tempdate);
-    }
-
-    private static String toLocaleString(double date) {
-        if (localeDateTimeFormatter == null)
-            localeDateTimeFormatter =
-                DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
-
-        return toLocale_helper(date, localeDateTimeFormatter);
-    }
-
-    private static String toLocaleTimeString(double date) {
-        if (localeTimeFormatter == null)
-            localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG);
-
-        return toLocale_helper(date, localeTimeFormatter);
-    }
-
-    private static String toLocaleDateString(double date) {
-        if (localeDateFormatter == null)
-            localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG);
-
-        return toLocale_helper(date, localeDateFormatter);
-    }
-
-    private static String toUTCString(double date) {
-        StringBuffer result = new StringBuffer(60);
-
-        String dateStr = Integer.toString(DateFromTime(date));
-        String hourStr = Integer.toString(HourFromTime(date));
-        String minStr = Integer.toString(MinFromTime(date));
-        String secStr = Integer.toString(SecFromTime(date));
-        int year = YearFromTime(date);
-        String yearStr = Integer.toString(year > 0 ? year : -year);
-
-        result.append(days[WeekDay(date)]);
-        result.append(", ");
-        if (dateStr.length() == 1)
-            result.append('0');
-        result.append(dateStr);
-        result.append(' ');
-        result.append(months[MonthFromTime(date)]);
-        if (year < 0)
-            result.append(" -");
-        else
-            result.append(' ');
-        int i;
-        for (i = yearStr.length(); i < 4; i++)
-            result.append('0');
-        result.append(yearStr);
-
-        if (hourStr.length() == 1)
-            result.append(" 0");
-        else
-            result.append(' ');
-        result.append(hourStr);
-        if (minStr.length() == 1)
-            result.append(":0");
-        else
-            result.append(':');
-        result.append(minStr);
-        if (secStr.length() == 1)
-            result.append(":0");
-        else
-            result.append(':');
-        result.append(secStr);
-
-        result.append(" GMT");
-        return result.toString();
-    }
-
-    private static double getYear(double date) {
-        int result = YearFromTime(LocalTime(date));
-        result -= 1900;
-        return result;
-    }
-
-    private static double getTimezoneOffset(double date) {
-        return (date - LocalTime(date)) / msPerMinute;
-    }
-
-    public double setTime(double time) {
-        this.date = TimeClip(time);
-        return this.date;
-    }
-
-    private double makeTime(JS[] args, int maxargs, boolean local) throws JSExn {
-        int i;
-        double conv[] = new double[4];
-        double hour, min, sec, msec;
-        double lorutime; /* Local or UTC version of date */
-
-        double time;
-        double result;
-
-        double date = this.date;
-
-        /* just return NaN if the date is already NaN */
-        if (date != date)
-            return date;
-
-        /* Satisfy the ECMA rule that if a function is called with
-         * fewer arguments than the specified formal arguments, the
-         * remaining arguments are set to undefined.  Seems like all
-         * the Date.setWhatever functions in ECMA are only varargs
-         * beyond the first argument; this should be set to undefined
-         * if it's not given.  This means that "d = new Date();
-         * d.setMilliseconds()" returns NaN.  Blech.
-         */
-        if (args.length == 0)
-            args = new JS[] { null };
-
-        for (i = 0; i < args.length && i < maxargs; i++) {
-            conv[i] = _toNumber(args[i]);
-
-            // limit checks that happen in MakeTime in ECMA.
-            if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
-                this.date = Double.NaN;
-                return this.date;
-            }
-            conv[i] = toDouble(conv[i]);
-        }
-
-        if (local)
-            lorutime = LocalTime(date);
-        else
-            lorutime = date;
-
-        i = 0;
-        int stop = args.length;
-
-        if (maxargs >= 4 && i < stop)
-            hour = conv[i++];
-        else
-            hour = HourFromTime(lorutime);
-
-        if (maxargs >= 3 && i < stop)
-            min = conv[i++];
-        else
-            min = MinFromTime(lorutime);
-
-        if (maxargs >= 2 && i < stop)
-            sec = conv[i++];
-        else
-            sec = SecFromTime(lorutime);
-
-        if (maxargs >= 1 && i < stop)
-            msec = conv[i++];
-        else
-            msec = msFromTime(lorutime);
-
-        time = MakeTime(hour, min, sec, msec);
-        result = MakeDate(Day(lorutime), time);
-
-        if (local)
-            result = internalUTC(result);
-        date = TimeClip(result);
-
-        this.date = date;
-        return date;
-    }
-
-    private double setHours(JS[] args) throws JSExn {
-        return makeTime(args, 4, true);
-    }
-
-    private double setUTCHours(JS[] args) throws JSExn {
-        return makeTime(args, 4, false);
-    }
-
-    private double makeDate(JS[] args, int maxargs, boolean local) throws JSExn {
-        int i;
-        double conv[] = new double[3];
-        double year, month, day;
-        double lorutime; /* local or UTC version of date */
-        double result;
-
-        double date = this.date;
-
-        /* See arg padding comment in makeTime.*/
-        if (args.length == 0)
-            args = new JS[] { null };
-
-        for (i = 0; i < args.length && i < maxargs; i++) {
-            conv[i] = _toNumber(args[i]);
-
-            // limit checks that happen in MakeDate in ECMA.
-            if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
-                this.date = Double.NaN;
-                return this.date;
-            }
-            conv[i] = toDouble(conv[i]);
-        }
-
-        /* return NaN if date is NaN and we're not setting the year,
-         * If we are, use 0 as the time. */
-        if (date != date) {
-            if (args.length < 3) {
-                return Double.NaN;
-            } else {
-                lorutime = 0;
-            }
-        } else {
-            if (local)
-                lorutime = LocalTime(date);
-            else
-                lorutime = date;
-        }
-
-        i = 0;
-        int stop = args.length;
-
-        if (maxargs >= 3 && i < stop)
-            year = conv[i++];
-        else
-            year = YearFromTime(lorutime);
-
-        if (maxargs >= 2 && i < stop)
-            month = conv[i++];
-        else
-            month = MonthFromTime(lorutime);
-
-        if (maxargs >= 1 && i < stop)
-            day = conv[i++];
-        else
-            day = DateFromTime(lorutime);
-
-        day = MakeDay(year, month, day); /* day within year */
-        result = MakeDate(day, TimeWithinDay(lorutime));
-
-        if (local)
-            result = internalUTC(result);
-
-        date = TimeClip(result);
-
-        this.date = date;
-        return date;
-    }
-
-    private double setYear(double year) {
-        double day, result;
-        if (year != year || Double.isInfinite(year)) {
-            this.date = Double.NaN;
-            return this.date;
-        }
-
-        if (this.date != this.date) {
-            this.date = 0;
-        } else {
-            this.date = LocalTime(this.date);
-        }
-
-        if (year >= 0 && year <= 99)
-            year += 1900;
-
-        day = MakeDay(year, MonthFromTime(this.date), DateFromTime(this.date));
-        result = MakeDate(day, TimeWithinDay(this.date));
-        result = internalUTC(result);
-
-        this.date = TimeClip(result);
-        return this.date;
-    }
-
-
-    //    private static final int
-    //        Id_toGMTString  =  Id_toUTCString; // Alias, see Ecma B.2.6
-// #/string_id_map#
-
-    /* cached values */
-    private static java.util.TimeZone thisTimeZone;
-    private static double LocalTZA;
-    private static java.text.DateFormat timeZoneFormatter;
-    private static java.text.DateFormat localeDateTimeFormatter;
-    private static java.text.DateFormat localeDateFormatter;
-    private static java.text.DateFormat localeTimeFormatter;
-
-    private double date;
-
-    public long getRawTime() { return (long)this.date; }
-}
-
-