2002/03/21 01:19:33
[org.ibex.core.git] / src / org / mozilla / javascript / NativeDate.java
diff --git a/src/org/mozilla/javascript/NativeDate.java b/src/org/mozilla/javascript/NativeDate.java
new file mode 100644 (file)
index 0000000..77615ea
--- /dev/null
@@ -0,0 +1,1707 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
+ *\r
+ * The contents of this file are subject to the Netscape Public\r
+ * License Version 1.1 (the "License"); you may not use this file\r
+ * except in compliance with the License. You may obtain a copy of\r
+ * the License at http://www.mozilla.org/NPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS\r
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
+ * implied. See the License for the specific language governing\r
+ * rights and limitations under the License.\r
+ *\r
+ * The Original Code is Rhino code, released\r
+ * May 6, 1999.\r
+ *\r
+ * The Initial Developer of the Original Code is Netscape\r
+ * Communications Corporation.  Portions created by Netscape are\r
+ * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
+ * Rights Reserved.\r
+ *\r
+ * Contributor(s):\r
+ * Norris Boyd\r
+ * Mike McCabe\r
+ *\r
+ * Alternatively, the contents of this file may be used under the\r
+ * terms of the GNU Public License (the "GPL"), in which case the\r
+ * provisions of the GPL are applicable instead of those above.\r
+ * If you wish to allow use of your version of this file only\r
+ * under the terms of the GPL and not to allow others to use your\r
+ * version of this file under the NPL, indicate your decision by\r
+ * deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL.  If you do not delete\r
+ * the provisions above, a recipient may use your version of this\r
+ * file under either the NPL or the GPL.\r
+ */\r
+\r
+package org.mozilla.javascript;\r
+\r
+import java.util.Date;\r
+import java.util.TimeZone;\r
+import java.util.Locale;\r
+import java.text.NumberFormat;\r
+import java.text.DateFormat;\r
+import java.text.SimpleDateFormat;\r
+\r
+/**\r
+ * This class implements the Date native object.\r
+ * See ECMA 15.9.\r
+ * @author Mike McCabe\r
+ */\r
+public class NativeDate extends IdScriptable {\r
+\r
+    public static void init(Context cx, Scriptable scope, boolean sealed) {\r
+        NativeDate obj = new NativeDate();\r
+        obj.prototypeFlag = true;\r
+        \r
+        // Set the value of the prototype Date to NaN ('invalid date');\r
+        obj.date = ScriptRuntime.NaN;\r
+\r
+        obj.addAsPrototype(MAX_PROTOTYPE_ID, cx, scope, sealed);\r
+    }\r
+    \r
+    public NativeDate() {\r
+        if (thisTimeZone == null) {\r
+            // j.u.TimeZone is synchronized, so setting class statics from it\r
+            // should be OK.\r
+            thisTimeZone = java.util.TimeZone.getDefault();\r
+            LocalTZA = thisTimeZone.getRawOffset();\r
+        }\r
+    }\r
+\r
+    public String getClassName() {\r
+        return "Date";\r
+    }\r
+\r
+    public Object getDefaultValue(Class typeHint) {\r
+        if (typeHint == null)\r
+            typeHint = ScriptRuntime.StringClass;\r
+        return super.getDefaultValue(typeHint);\r
+    }\r
+\r
+    protected void fillConstructorProperties\r
+        (Context cx, IdFunction ctor, boolean sealed)\r
+    {\r
+        addIdFunctionProperty(ctor, ConstructorId_UTC, sealed);\r
+        addIdFunctionProperty(ctor, ConstructorId_parse, sealed);\r
+        super.fillConstructorProperties(cx, ctor, sealed);\r
+    }\r
+\r
+    public int methodArity(int methodId) {\r
+        if (prototypeFlag) {\r
+            switch (methodId) {\r
+                case ConstructorId_UTC:     return 1;\r
+                case ConstructorId_parse:   return 1;\r
+                case Id_constructor:        return 1; \r
+                case Id_toString:           return 0;\r
+                case Id_toTimeString:       return 0;\r
+                case Id_toDateString:       return 0;\r
+                case Id_toLocaleString:     return 0;\r
+                case Id_toLocaleTimeString: return 0;\r
+                case Id_toLocaleDateString: return 0;\r
+                case Id_toUTCString:        return 0;\r
+                case Id_valueOf:            return 0;\r
+                case Id_getTime:            return 0;\r
+                case Id_getYear:            return 0;\r
+                case Id_getFullYear:        return 0;\r
+                case Id_getUTCFullYear:     return 0;\r
+                case Id_getMonth:           return 0;\r
+                case Id_getUTCMonth:        return 0;\r
+                case Id_getDate:            return 0;\r
+                case Id_getUTCDate:         return 0;\r
+                case Id_getDay:             return 0;\r
+                case Id_getUTCDay:          return 0;\r
+                case Id_getHours:           return 0;\r
+                case Id_getUTCHours:        return 0;\r
+                case Id_getMinutes:         return 0;\r
+                case Id_getUTCMinutes:      return 0;\r
+                case Id_getSeconds:         return 0;\r
+                case Id_getUTCSeconds:      return 0;\r
+                case Id_getMilliseconds:    return 0;\r
+                case Id_getUTCMilliseconds: return 0;\r
+                case Id_getTimezoneOffset:  return 0;\r
+                case Id_setTime:            return 1;\r
+                case Id_setMilliseconds:    return 1;\r
+                case Id_setUTCMilliseconds: return 1;\r
+                case Id_setSeconds:         return 2;\r
+                case Id_setUTCSeconds:      return 2;\r
+                case Id_setMinutes:         return 3;\r
+                case Id_setUTCMinutes:      return 3;\r
+                case Id_setHours:           return 4;\r
+                case Id_setUTCHours:        return 4;\r
+                case Id_setDate:            return 1;\r
+                case Id_setUTCDate:         return 1;\r
+                case Id_setMonth:           return 2;\r
+                case Id_setUTCMonth:        return 2;\r
+                case Id_setFullYear:        return 3;\r
+                case Id_setUTCFullYear:     return 3;\r
+                case Id_setYear:            return 1;\r
+            }\r
+        }\r
+        return super.methodArity(methodId);\r
+    }\r
+\r
+    public Object execMethod\r
+        (int methodId, IdFunction f,\r
+         Context cx, Scriptable scope, Scriptable thisObj, Object[] args)\r
+        throws JavaScriptException\r
+    {\r
+        if (prototypeFlag) {\r
+            switch (methodId) {\r
+                case ConstructorId_UTC: \r
+                    return wrap_double(jsStaticFunction_UTC(args));\r
+\r
+                case ConstructorId_parse: \r
+                    return wrap_double(jsStaticFunction_parse\r
+                        (ScriptRuntime.toString(args, 0)));\r
+\r
+                case Id_constructor:\r
+                    return jsConstructor(args, thisObj == null);\r
+\r
+                case Id_toString: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    return date_format(t, FORMATSPEC_FULL);\r
+                }\r
+\r
+                case Id_toTimeString: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    return date_format(t, FORMATSPEC_TIME);\r
+                }\r
+\r
+                case Id_toDateString: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    return date_format(t, FORMATSPEC_DATE);\r
+                }\r
+\r
+                case Id_toLocaleString: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    return jsFunction_toLocaleString(t);\r
+                }\r
+\r
+                case Id_toLocaleTimeString: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    return jsFunction_toLocaleTimeString(t);\r
+                }\r
+\r
+                case Id_toLocaleDateString: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    return jsFunction_toLocaleDateString(t);\r
+                }\r
+\r
+                case Id_toUTCString: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { return jsFunction_toUTCString(t); }\r
+                    return jsFunction_NaN_date_str;\r
+                }\r
+\r
+                case Id_valueOf: \r
+                    return wrap_double(realThis(thisObj, f, true).date);\r
+\r
+                case Id_getTime: \r
+                    return wrap_double(realThis(thisObj, f, true).date);\r
+\r
+                case Id_getYear: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = jsFunction_getYear(cx, t); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getFullYear: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = YearFromTime(LocalTime(t)); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getUTCFullYear: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = YearFromTime(t); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getMonth: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = MonthFromTime(LocalTime(t)); }\r
+                    return wrap_double(t);\r
+                }\r
+                \r
+                case Id_getUTCMonth: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = MonthFromTime(t); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getDate: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = DateFromTime(LocalTime(t)); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getUTCDate: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = DateFromTime(t); }\r
+                    return wrap_double(t);\r
+                } \r
+\r
+                case Id_getDay: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = WeekDay(LocalTime(t)); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getUTCDay: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = WeekDay(t); }\r
+                    return wrap_double(t);\r
+                } \r
+\r
+                case Id_getHours: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = HourFromTime(LocalTime(t)); }\r
+                    return wrap_double(t);\r
+                } \r
+\r
+                case Id_getUTCHours: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = HourFromTime(t); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getMinutes: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = MinFromTime(LocalTime(t)); }\r
+                    return wrap_double(t);\r
+                } \r
+\r
+                case Id_getUTCMinutes: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = MinFromTime(t); }\r
+                    return wrap_double(t);\r
+                } \r
+\r
+                case Id_getSeconds: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = SecFromTime(LocalTime(t)); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getUTCSeconds: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = SecFromTime(t); }\r
+                    return wrap_double(t);\r
+                }\r
+                \r
+                case Id_getMilliseconds: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = msFromTime(LocalTime(t)); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_getUTCMilliseconds: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = msFromTime(t); }\r
+                    return wrap_double(t);\r
+                }\r
+                \r
+                case Id_getTimezoneOffset: {\r
+                    double t = realThis(thisObj, f, true).date;\r
+                    if (t == t) { t = jsFunction_getTimezoneOffset(t); }\r
+                    return wrap_double(t);\r
+                }\r
+\r
+                case Id_setTime: \r
+                    return wrap_double(realThis(thisObj, f, true).\r
+                        jsFunction_setTime(ScriptRuntime.toNumber(args, 0)));\r
+\r
+                case Id_setMilliseconds: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeTime(args, 1, true));\r
+\r
+                case Id_setUTCMilliseconds: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeTime(args, 1, false));\r
+\r
+                case Id_setSeconds: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeTime(args, 2, true));\r
+\r
+                case Id_setUTCSeconds: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeTime(args, 2, false));\r
+\r
+                case Id_setMinutes: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeTime(args, 3, true));\r
+\r
+                case Id_setUTCMinutes: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeTime(args, 3, false));\r
+\r
+                case Id_setHours: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeTime(args, 4, true));\r
+\r
+                case Id_setUTCHours: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeTime(args, 4, false));\r
+\r
+                case Id_setDate: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeDate(args, 1, true));\r
+\r
+                case Id_setUTCDate: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeDate(args, 1, false));\r
+\r
+                case Id_setMonth: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeDate(args, 2, true));\r
+\r
+                case Id_setUTCMonth: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeDate(args, 2, false));\r
+\r
+                case Id_setFullYear: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeDate(args, 3, true));\r
+\r
+                case Id_setUTCFullYear: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        makeDate(args, 3, false));\r
+\r
+                case Id_setYear: \r
+                    return wrap_double(realThis(thisObj, f, false).\r
+                        jsFunction_setYear(ScriptRuntime.toNumber(args, 0)));\r
+            }\r
+        }\r
+\r
+        return super.execMethod(methodId, f, cx, scope, thisObj, args);\r
+    }\r
+\r
+    private NativeDate realThis(Scriptable thisObj, IdFunction f, \r
+                                boolean readOnly)\r
+    {\r
+        while (!(thisObj instanceof NativeDate)) {\r
+            thisObj = nextInstanceCheck(thisObj, f, readOnly);\r
+        }\r
+        return (NativeDate)thisObj;\r
+    }\r
+\r
+    /* ECMA helper functions */\r
+\r
+    private static final double HalfTimeDomain = 8.64e15;\r
+    private static final double HoursPerDay    = 24.0;\r
+    private static final double MinutesPerHour = 60.0;\r
+    private static final double SecondsPerMinute = 60.0;\r
+    private static final double msPerSecond    = 1000.0;\r
+    private static final double MinutesPerDay  = (HoursPerDay * MinutesPerHour);\r
+    private static final double SecondsPerDay  = (MinutesPerDay * SecondsPerMinute);\r
+    private static final double SecondsPerHour = (MinutesPerHour * SecondsPerMinute);\r
+    private static final double msPerDay       = (SecondsPerDay * msPerSecond);\r
+    private static final double msPerHour      = (SecondsPerHour * msPerSecond);\r
+    private static final double msPerMinute    = (SecondsPerMinute * msPerSecond);\r
+\r
+    private static double Day(double t) {\r
+        return Math.floor(t / msPerDay);\r
+    }\r
+\r
+    private static double TimeWithinDay(double t) {\r
+        double result;\r
+        result = t % msPerDay;\r
+        if (result < 0)\r
+            result += msPerDay;\r
+        return result;\r
+    }\r
+\r
+    private static int DaysInYear(int y) {\r
+        if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))\r
+            return 366;\r
+        else\r
+            return 365;\r
+    }\r
+\r
+\r
+    /* math here has to be f.p, because we need\r
+     *  floor((1968 - 1969) / 4) == -1\r
+     */\r
+    private static double DayFromYear(double y) {\r
+        return ((365 * ((y)-1970) + Math.floor(((y)-1969)/4.0)\r
+                 - Math.floor(((y)-1901)/100.0) + Math.floor(((y)-1601)/400.0)));\r
+    }\r
+\r
+    private static double TimeFromYear(double y) {\r
+        return DayFromYear(y) * msPerDay;\r
+    }\r
+\r
+    private static int YearFromTime(double t) {\r
+        int lo = (int) Math.floor((t / msPerDay) / 366) + 1970;\r
+        int hi = (int) Math.floor((t / msPerDay) / 365) + 1970;\r
+        int mid;\r
+\r
+        /* above doesn't work for negative dates... */\r
+        if (hi < lo) {\r
+            int temp = lo;\r
+            lo = hi;\r
+            hi = temp;\r
+        }\r
+\r
+        /* Use a simple binary search algorithm to find the right\r
+           year.  This seems like brute force... but the computation\r
+           of hi and lo years above lands within one year of the\r
+           correct answer for years within a thousand years of\r
+           1970; the loop below only requires six iterations\r
+           for year 270000. */\r
+        while (hi > lo) {\r
+            mid = (hi + lo) / 2;\r
+            if (TimeFromYear(mid) > t) {\r
+                hi = mid - 1;\r
+            } else {\r
+                if (TimeFromYear(mid) <= t) {\r
+                    int temp = mid + 1;\r
+                    if (TimeFromYear(temp) > t) {\r
+                        return mid;\r
+                    }\r
+                    lo = mid + 1;\r
+                }\r
+            }\r
+        }\r
+        return lo;\r
+    }\r
+\r
+    private static boolean InLeapYear(double t) {\r
+        return DaysInYear(YearFromTime(t)) == 366;\r
+    }\r
+\r
+    private static int DayWithinYear(double t) {\r
+        int year = YearFromTime(t);\r
+        return (int) (Day(t) - DayFromYear(year));\r
+    }\r
+    /*\r
+     * The following array contains the day of year for the first day of\r
+     * each month, where index 0 is January, and day 0 is January 1.\r
+     */\r
+\r
+    private static double DayFromMonth(int m, boolean leap) {\r
+        int day = m * 30;\r
+\r
+        if (m >= 7) { day += m / 2 - 1; }\r
+        else if (m >= 2) { day += (m - 1) / 2 - 1; }\r
+        else { day += m; }\r
+\r
+        if (leap && m >= 2) { ++day; }\r
+\r
+        return day;\r
+    }\r
+\r
+    private static int MonthFromTime(double t) {\r
+        int d, step;\r
+\r
+        d = DayWithinYear(t);\r
+\r
+        if (d < (step = 31))\r
+            return 0;\r
+\r
+        // Originally coded as step += (InLeapYear(t) ? 29 : 28);\r
+        // but some jits always returned 28!\r
+        if (InLeapYear(t))\r
+            step += 29;\r
+        else\r
+            step += 28;\r
+\r
+        if (d < step)\r
+            return 1;\r
+        if (d < (step += 31))\r
+            return 2;\r
+        if (d < (step += 30))\r
+            return 3;\r
+        if (d < (step += 31))\r
+            return 4;\r
+        if (d < (step += 30))\r
+            return 5;\r
+        if (d < (step += 31))\r
+            return 6;\r
+        if (d < (step += 31))\r
+            return 7;\r
+        if (d < (step += 30))\r
+            return 8;\r
+        if (d < (step += 31))\r
+            return 9;\r
+        if (d < (step += 30))\r
+            return 10;\r
+        return 11;\r
+    }\r
+\r
+    private static int DateFromTime(double t) {\r
+        int d, step, next;\r
+\r
+        d = DayWithinYear(t);\r
+        if (d <= (next = 30))\r
+            return d + 1;\r
+        step = next;\r
+\r
+        // Originally coded as next += (InLeapYear(t) ? 29 : 28);\r
+        // but some jits always returned 28!\r
+        if (InLeapYear(t))\r
+            next += 29;\r
+        else\r
+            next += 28;\r
+\r
+        if (d <= next)\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 31))\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 30))\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 31))\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 30))\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 31))\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 31))\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 30))\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 31))\r
+            return d - step;\r
+        step = next;\r
+        if (d <= (next += 30))\r
+            return d - step;\r
+        step = next;\r
+\r
+        return d - step;\r
+    }\r
+\r
+    private static int WeekDay(double t) {\r
+        double result;\r
+        result = Day(t) + 4;\r
+        result = result % 7;\r
+        if (result < 0)\r
+            result += 7;\r
+        return (int) result;\r
+    }\r
+\r
+    private static double Now() {\r
+        return (double) System.currentTimeMillis();\r
+    }\r
+\r
+    /* Should be possible to determine the need for this dynamically\r
+     * if we go with the workaround... I'm not using it now, because I\r
+     * can't think of any clean way to make toLocaleString() and the\r
+     * time zone (comment) in toString match the generated string\r
+     * values.  Currently it's wrong-but-consistent in all but the\r
+     * most recent betas of the JRE - seems to work in 1.1.7.\r
+     */\r
+    private final static boolean TZO_WORKAROUND = false;\r
+    private static double DaylightSavingTA(double t) {\r
+        if (!TZO_WORKAROUND) {\r
+            Date date = new Date((long) t);\r
+            if (thisTimeZone.inDaylightTime(date))\r
+                return msPerHour;\r
+            else\r
+                return 0;\r
+        } else {\r
+            /* Use getOffset if inDaylightTime() is broken, because it\r
+             * seems to work acceptably.  We don't switch over to it\r
+             * entirely, because it requires (expensive) exploded date arguments,\r
+             * and the api makes it impossible to handle dst\r
+             * changeovers cleanly.\r
+             */\r
+\r
+            // Hardcode the assumption that the changeover always\r
+            // happens at 2:00 AM:\r
+            t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);\r
+\r
+            int year = YearFromTime(t);\r
+            double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0,\r
+                                                   year,\r
+                                                   MonthFromTime(t),\r
+                                                   DateFromTime(t),\r
+                                                   WeekDay(t),\r
+                                                   (int)TimeWithinDay(t));\r
+\r
+            if ((offset - LocalTZA) != 0)\r
+                return msPerHour;\r
+            else\r
+                return 0;\r
+            //         return offset - LocalTZA;\r
+        }\r
+    }\r
+\r
+    private static double LocalTime(double t) {\r
+        return t + LocalTZA + DaylightSavingTA(t);\r
+    }\r
+\r
+    public static double internalUTC(double t) {\r
+        return t - LocalTZA - DaylightSavingTA(t - LocalTZA);\r
+    }\r
+\r
+    private static int HourFromTime(double t) {\r
+        double result;\r
+        result = Math.floor(t / msPerHour) % HoursPerDay;\r
+        if (result < 0)\r
+            result += HoursPerDay;\r
+        return (int) result;\r
+    }\r
+\r
+    private static int MinFromTime(double t) {\r
+        double result;\r
+        result = Math.floor(t / msPerMinute) % MinutesPerHour;\r
+        if (result < 0)\r
+            result += MinutesPerHour;\r
+        return (int) result;\r
+    }\r
+\r
+    private static int SecFromTime(double t) {\r
+        double result;\r
+        result = Math.floor(t / msPerSecond) % SecondsPerMinute;\r
+        if (result < 0)\r
+            result += SecondsPerMinute;\r
+        return (int) result;\r
+    }\r
+\r
+    private static int msFromTime(double t) {\r
+        double result;\r
+        result =  t % msPerSecond;\r
+        if (result < 0)\r
+            result += msPerSecond;\r
+        return (int) result;\r
+    }\r
+\r
+    private static double MakeTime(double hour, double min,\r
+                                   double sec, double ms)\r
+    {\r
+        return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)\r
+            * msPerSecond + ms;\r
+    }\r
+\r
+    private static double MakeDay(double year, double month, double date) {\r
+        double result;\r
+        boolean leap;\r
+        double yearday;\r
+        double monthday;\r
+\r
+        year += Math.floor(month / 12);\r
+\r
+        month = month % 12;\r
+        if (month < 0)\r
+            month += 12;\r
+\r
+        leap = (DaysInYear((int) year) == 366);\r
+\r
+        yearday = Math.floor(TimeFromYear(year) / msPerDay);\r
+        monthday = DayFromMonth((int) month, leap);\r
+\r
+        result = yearday\r
+            + monthday\r
+            + date - 1;\r
+        return result;\r
+    }\r
+\r
+    private static double MakeDate(double day, double time) {\r
+        return day * msPerDay + time;\r
+    }\r
+\r
+    private static double TimeClip(double d) {\r
+        if (d != d ||\r
+            d == Double.POSITIVE_INFINITY ||\r
+            d == Double.NEGATIVE_INFINITY ||\r
+            Math.abs(d) > HalfTimeDomain)\r
+        {\r
+            return ScriptRuntime.NaN;\r
+        }\r
+        if (d > 0.0)\r
+            return Math.floor(d + 0.);\r
+        else\r
+            return Math.ceil(d + 0.);\r
+    }\r
+\r
+    /* end of ECMA helper functions */\r
+\r
+    /* find UTC time from given date... no 1900 correction! */\r
+    public static double date_msecFromDate(double year, double mon,\r
+                                            double mday, double hour,\r
+                                            double min, double sec,\r
+                                            double msec)\r
+    {\r
+        double day;\r
+        double time;\r
+        double result;\r
+\r
+        day = MakeDay(year, mon, mday);\r
+        time = MakeTime(hour, min, sec, msec);\r
+        result = MakeDate(day, time);\r
+        return result;\r
+    }\r
+\r
+\r
+    private static final int MAXARGS = 7;\r
+    private static double jsStaticFunction_UTC(Object[] args) {\r
+        double array[] = new double[MAXARGS];\r
+        int loop;\r
+        double d;\r
+\r
+        for (loop = 0; loop < MAXARGS; loop++) {\r
+            if (loop < args.length) {\r
+                d = ScriptRuntime.toNumber(args[loop]);\r
+                if (d != d || Double.isInfinite(d)) {\r
+                    return ScriptRuntime.NaN;\r
+                }\r
+                array[loop] = ScriptRuntime.toInteger(args[loop]);\r
+            } else {\r
+                array[loop] = 0;\r
+            }\r
+        }\r
+\r
+        /* adjust 2-digit years into the 20th century */\r
+        if (array[0] >= 0 && array[0] <= 99)\r
+            array[0] += 1900;\r
+\r
+            /* if we got a 0 for 'date' (which is out of range)\r
+             * pretend it's a 1.  (So Date.UTC(1972, 5) works) */\r
+        if (array[2] < 1)\r
+            array[2] = 1;\r
+\r
+        d = date_msecFromDate(array[0], array[1], array[2],\r
+                              array[3], array[4], array[5], array[6]);\r
+        d = TimeClip(d);\r
+        return d;\r
+        //        return new Double(d);\r
+    }\r
+\r
+    /*\r
+     * Use ported code from jsdate.c rather than the locale-specific\r
+     * date-parsing code from Java, to keep js and rhino consistent.\r
+     * Is this the right strategy?\r
+     */\r
+\r
+    /* for use by date_parse */\r
+\r
+    /* replace this with byte arrays?  Cheaper? */\r
+    private static String wtb[] = {\r
+        "am", "pm",\r
+        "monday", "tuesday", "wednesday", "thursday", "friday",\r
+        "saturday", "sunday",\r
+        "january", "february", "march", "april", "may", "june",\r
+        "july", "august", "september", "october", "november", "december",\r
+        "gmt", "ut", "utc", "est", "edt", "cst", "cdt",\r
+        "mst", "mdt", "pst", "pdt"\r
+        /* time zone table needs to be expanded */\r
+    };\r
+\r
+    private static int ttb[] = {\r
+        -1, -2, 0, 0, 0, 0, 0, 0, 0,     /* AM/PM */\r
+        2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,\r
+        10000 + 0, 10000 + 0, 10000 + 0, /* UT/UTC */\r
+        10000 + 5 * 60, 10000 + 4 * 60,  /* EDT */\r
+        10000 + 6 * 60, 10000 + 5 * 60,\r
+        10000 + 7 * 60, 10000 + 6 * 60,\r
+        10000 + 8 * 60, 10000 + 7 * 60\r
+    };\r
+\r
+    /* helper for date_parse */\r
+    private static boolean date_regionMatches(String s1, int s1off,\r
+                                              String s2, int s2off,\r
+                                              int count)\r
+    {\r
+        boolean result = false;\r
+        /* return true if matches, otherwise, false */\r
+        int s1len = s1.length();\r
+        int s2len = s2.length();\r
+\r
+        while (count > 0 && s1off < s1len && s2off < s2len) {\r
+            if (Character.toLowerCase(s1.charAt(s1off)) !=\r
+                Character.toLowerCase(s2.charAt(s2off)))\r
+                break;\r
+            s1off++;\r
+            s2off++;\r
+            count--;\r
+        }\r
+\r
+        if (count == 0) {\r
+            result = true;\r
+        }\r
+        return result;\r
+    }\r
+\r
+    private static double date_parseString(String s) {\r
+        double msec;\r
+\r
+        int year = -1;\r
+        int mon = -1;\r
+        int mday = -1;\r
+        int hour = -1;\r
+        int min = -1;\r
+        int sec = -1;\r
+        char c = 0;\r
+        char si = 0;\r
+        int i = 0;\r
+        int n = -1;\r
+        double tzoffset = -1;\r
+        char prevc = 0;\r
+        int limit = 0;\r
+        boolean seenplusminus = false;\r
+\r
+        if (s == null)  // ??? Will s be null?\r
+            return ScriptRuntime.NaN;\r
+        limit = s.length();\r
+        while (i < limit) {\r
+            c = s.charAt(i);\r
+            i++;\r
+            if (c <= ' ' || c == ',' || c == '-') {\r
+                if (i < limit) {\r
+                    si = s.charAt(i);\r
+                    if (c == '-' && '0' <= si && si <= '9') {\r
+                        prevc = c;\r
+                    }\r
+                }\r
+                continue;\r
+            }\r
+            if (c == '(') { /* comments) */\r
+                int depth = 1;\r
+                while (i < limit) {\r
+                    c = s.charAt(i);\r
+                    i++;\r
+                    if (c == '(')\r
+                        depth++;\r
+                    else if (c == ')')\r
+                        if (--depth <= 0)\r
+                            break;\r
+                }\r
+                continue;\r
+            }\r
+            if ('0' <= c && c <= '9') {\r
+                n = c - '0';\r
+                while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {\r
+                    n = n * 10 + c - '0';\r
+                    i++;\r
+                }\r
+\r
+                /* allow TZA before the year, so\r
+                 * 'Wed Nov 05 21:49:11 GMT-0800 1997'\r
+                 * works */\r
+\r
+                /* uses of seenplusminus allow : in TZA, so Java\r
+                 * no-timezone style of GMT+4:30 works\r
+                 */\r
+                if ((prevc == '+' || prevc == '-')/*  && year>=0 */) {\r
+                    /* make ':' case below change tzoffset */\r
+                    seenplusminus = true;\r
+\r
+                    /* offset */\r
+                    if (n < 24)\r
+                        n = n * 60; /* EG. "GMT-3" */\r
+                    else\r
+                        n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */\r
+                    if (prevc == '+')       /* plus means east of GMT */\r
+                        n = -n;\r
+                    if (tzoffset != 0 && tzoffset != -1)\r
+                        return ScriptRuntime.NaN;\r
+                    tzoffset = n;\r
+                } else if (n >= 70  ||\r
+                           (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {\r
+                    if (year >= 0)\r
+                        return ScriptRuntime.NaN;\r
+                    else if (c <= ' ' || c == ',' || c == '/' || i >= limit)\r
+                        year = n < 100 ? n + 1900 : n;\r
+                    else\r
+                        return ScriptRuntime.NaN;\r
+                } else if (c == ':') {\r
+                    if (hour < 0)\r
+                        hour = /*byte*/ n;\r
+                    else if (min < 0)\r
+                        min = /*byte*/ n;\r
+                    else\r
+                        return ScriptRuntime.NaN;\r
+                } else if (c == '/') {\r
+                    if (mon < 0)\r
+                        mon = /*byte*/ n-1;\r
+                    else if (mday < 0)\r
+                        mday = /*byte*/ n;\r
+                    else\r
+                        return ScriptRuntime.NaN;\r
+                } else if (i < limit && c != ',' && c > ' ' && c != '-') {\r
+                    return ScriptRuntime.NaN;\r
+                } else if (seenplusminus && n < 60) {  /* handle GMT-3:30 */\r
+                    if (tzoffset < 0)\r
+                        tzoffset -= n;\r
+                    else\r
+                        tzoffset += n;\r
+                } else if (hour >= 0 && min < 0) {\r
+                    min = /*byte*/ n;\r
+                } else if (min >= 0 && sec < 0) {\r
+                    sec = /*byte*/ n;\r
+                } else if (mday < 0) {\r
+                    mday = /*byte*/ n;\r
+                } else {\r
+                    return ScriptRuntime.NaN;\r
+                }\r
+                prevc = 0;\r
+            } else if (c == '/' || c == ':' || c == '+' || c == '-') {\r
+                prevc = c;\r
+            } else {\r
+                int st = i - 1;\r
+                int k;\r
+                while (i < limit) {\r
+                    c = s.charAt(i);\r
+                    if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))\r
+                        break;\r
+                    i++;\r
+                }\r
+                if (i <= st + 1)\r
+                    return ScriptRuntime.NaN;\r
+                for (k = wtb.length; --k >= 0;)\r
+                    if (date_regionMatches(wtb[k], 0, s, st, i-st)) {\r
+                        int action = ttb[k];\r
+                        if (action != 0) {\r
+                            if (action < 0) {\r
+                                /*\r
+                                 * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as\r
+                                 * 12:30, instead of blindly adding 12 if PM.\r
+                                 */\r
+                                if (hour > 12 || hour < 0) {\r
+                                    return ScriptRuntime.NaN;\r
+                                } else {\r
+                                    if (action == -1 && hour == 12) { // am\r
+                                        hour = 0;\r
+                                    } else if (action == -2 && hour != 12) {// pm\r
+                                        hour += 12;\r
+                                    }\r
+                                }\r
+                            } else if (action <= 13) { /* month! */\r
+                                if (mon < 0) {\r
+                                    mon = /*byte*/ (action - 2);\r
+                                } else {\r
+                                    return ScriptRuntime.NaN;\r
+                                }\r
+                            } else {\r
+                                tzoffset = action - 10000;\r
+                            }\r
+                        }\r
+                        break;\r
+                    }\r
+                if (k < 0)\r
+                    return ScriptRuntime.NaN;\r
+                prevc = 0;\r
+            }\r
+        }\r
+        if (year < 0 || mon < 0 || mday < 0)\r
+            return ScriptRuntime.NaN;\r
+        if (sec < 0)\r
+            sec = 0;\r
+        if (min < 0)\r
+            min = 0;\r
+        if (hour < 0)\r
+            hour = 0;\r
+        if (tzoffset == -1) { /* no time zone specified, have to use local */\r
+            double time;\r
+            time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);\r
+            return internalUTC(time);\r
+        }\r
+\r
+        msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);\r
+        msec += tzoffset * msPerMinute;\r
+        return msec;\r
+    }\r
+\r
+    private static double jsStaticFunction_parse(String s) {\r
+        return date_parseString(s);\r
+    }\r
+\r
+    private static final int FORMATSPEC_FULL = 0;\r
+    private static final int FORMATSPEC_DATE = 1;\r
+    private static final int FORMATSPEC_TIME = 2;\r
+\r
+    private static String date_format(double t, int format) {\r
+        if (t != t)\r
+            return jsFunction_NaN_date_str;\r
+\r
+        StringBuffer result = new StringBuffer(60);\r
+        double local = LocalTime(t);\r
+\r
+        /* offset from GMT in minutes.  The offset includes daylight savings,\r
+           if it applies. */\r
+        int minutes = (int) Math.floor((LocalTZA + DaylightSavingTA(t))\r
+                                       / msPerMinute);\r
+        /* map 510 minutes to 0830 hours */\r
+        int offset = (minutes / 60) * 100 + minutes % 60;\r
+\r
+        String dateStr = Integer.toString(DateFromTime(local));\r
+        String hourStr = Integer.toString(HourFromTime(local));\r
+        String minStr = Integer.toString(MinFromTime(local));\r
+        String secStr = Integer.toString(SecFromTime(local));\r
+        String offsetStr = Integer.toString(offset > 0 ? offset : -offset);\r
+        int year = YearFromTime(local);\r
+        String yearStr = Integer.toString(year > 0 ? year : -year);\r
+\r
+        /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */\r
+        /* Tue Oct 31 2000 */\r
+        /* 09:41:40 GMT-0800 (PST) */\r
+\r
+        if (format != FORMATSPEC_TIME) {\r
+            result.append(days[WeekDay(local)]);\r
+            result.append(' ');\r
+            result.append(months[MonthFromTime(local)]);\r
+            if (dateStr.length() == 1)\r
+                result.append(" 0");\r
+            else\r
+                result.append(' ');\r
+            result.append(dateStr);\r
+            result.append(' ');\r
+        }\r
+\r
+        if (format != FORMATSPEC_DATE) {\r
+            if (hourStr.length() == 1)\r
+                result.append('0');\r
+            result.append(hourStr);\r
+            if (minStr.length() == 1)\r
+                result.append(":0");\r
+            else\r
+                result.append(':');\r
+            result.append(minStr);\r
+            if (secStr.length() == 1)\r
+                result.append(":0");\r
+            else\r
+                result.append(':');\r
+            result.append(secStr);\r
+            if (offset > 0)\r
+                result.append(" GMT+");\r
+            else\r
+                result.append(" GMT-");\r
+            for (int i = offsetStr.length(); i < 4; i++)\r
+                result.append('0');\r
+            result.append(offsetStr);\r
+\r
+            if (timeZoneFormatter == null)\r
+                timeZoneFormatter = new java.text.SimpleDateFormat("zzz");\r
+\r
+            if (timeZoneFormatter != null) {\r
+                result.append(" (");\r
+                java.util.Date date = new Date((long) t);\r
+                result.append(timeZoneFormatter.format(date));\r
+                result.append(')');\r
+            }\r
+            if (format != FORMATSPEC_TIME)\r
+                result.append(' ');\r
+        }\r
+\r
+        if (format != FORMATSPEC_TIME) {\r
+            if (year < 0)\r
+                result.append('-');\r
+            for (int i = yearStr.length(); i < 4; i++)\r
+                result.append('0');\r
+            result.append(yearStr);\r
+        }\r
+\r
+        return result.toString();\r
+    }\r
+\r
+    /* the javascript constructor */\r
+    private static Object jsConstructor(Object[] args, boolean inNewExpr) {\r
+        // if called as a function, just return a string\r
+        // representing the current time.\r
+        if (!inNewExpr)\r
+            return date_format(Now(), FORMATSPEC_FULL);\r
+\r
+        NativeDate obj = new NativeDate();\r
+\r
+        // if called as a constructor with no args,\r
+        // return a new Date with the current time.\r
+        if (args.length == 0) {\r
+            obj.date = Now();\r
+            return obj;\r
+        }\r
+\r
+        // if called with just one arg -\r
+        if (args.length == 1) {\r
+            double date;\r
+            if (args[0] instanceof Scriptable)\r
+                args[0] = ((Scriptable) args[0]).getDefaultValue(null);\r
+            if (!(args[0] instanceof String)) {\r
+                // if it's not a string, use it as a millisecond date\r
+                date = ScriptRuntime.toNumber(args[0]);\r
+            } else {\r
+                // it's a string; parse it.\r
+                String str = (String) args[0];\r
+                date = date_parseString(str);\r
+            }\r
+            obj.date = TimeClip(date);\r
+            return obj;\r
+        }\r
+\r
+        // multiple arguments; year, month, day etc.\r
+        double array[] = new double[MAXARGS];\r
+        int loop;\r
+        double d;\r
+\r
+        for (loop = 0; loop < MAXARGS; loop++) {\r
+            if (loop < args.length) {\r
+                d = ScriptRuntime.toNumber(args[loop]);\r
+\r
+                if (d != d || Double.isInfinite(d)) {\r
+                    obj.date = ScriptRuntime.NaN;\r
+                    return obj;\r
+                }\r
+                array[loop] = ScriptRuntime.toInteger(args[loop]);\r
+            } else {\r
+                array[loop] = 0;\r
+            }\r
+        }\r
+\r
+        /* adjust 2-digit years into the 20th century */\r
+        if (array[0] >= 0 && array[0] <= 99)\r
+            array[0] += 1900;\r
+\r
+        /* if we got a 0 for 'date' (which is out of range)\r
+         * pretend it's a 1 */\r
+        if (array[2] < 1)\r
+            array[2] = 1;\r
+\r
+        double day = MakeDay(array[0], array[1], array[2]);\r
+        double time = MakeTime(array[3], array[4], array[5], array[6]);\r
+        time = MakeDate(day, time);\r
+        time = internalUTC(time);\r
+        obj.date = TimeClip(time);\r
+\r
+        return obj;\r
+    }\r
+\r
+    /* constants for toString, toUTCString */\r
+    private static String jsFunction_NaN_date_str = "Invalid Date";\r
+\r
+    private static String[] days = {\r
+        "Sun","Mon","Tue","Wed","Thu","Fri","Sat"\r
+    };\r
+\r
+    private static String[] months = {\r
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r
+        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r
+    };\r
+\r
+    private static String toLocale_helper(double t,\r
+                                          java.text.DateFormat formatter)\r
+    {\r
+        if (t != t)\r
+            return jsFunction_NaN_date_str;\r
+\r
+        java.util.Date tempdate = new Date((long) t);\r
+        return formatter.format(tempdate);\r
+    }\r
+\r
+    private static String jsFunction_toLocaleString(double date) {\r
+        if (localeDateTimeFormatter == null)\r
+            localeDateTimeFormatter =\r
+                DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);\r
+\r
+        return toLocale_helper(date, localeDateTimeFormatter);\r
+    }\r
+\r
+    private static String jsFunction_toLocaleTimeString(double date) {\r
+        if (localeTimeFormatter == null)\r
+            localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG);\r
+\r
+        return toLocale_helper(date, localeTimeFormatter);\r
+    }\r
+\r
+    private static String jsFunction_toLocaleDateString(double date) {\r
+        if (localeDateFormatter == null)\r
+            localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG);\r
+\r
+        return toLocale_helper(date, localeDateFormatter);\r
+    }\r
+\r
+    private static String jsFunction_toUTCString(double date) {\r
+        StringBuffer result = new StringBuffer(60);\r
+\r
+        String dateStr = Integer.toString(DateFromTime(date));\r
+        String hourStr = Integer.toString(HourFromTime(date));\r
+        String minStr = Integer.toString(MinFromTime(date));\r
+        String secStr = Integer.toString(SecFromTime(date));\r
+        int year = YearFromTime(date);\r
+        String yearStr = Integer.toString(year > 0 ? year : -year);\r
+\r
+        result.append(days[WeekDay(date)]);\r
+        result.append(", ");\r
+        if (dateStr.length() == 1)\r
+            result.append('0');\r
+        result.append(dateStr);\r
+        result.append(' ');\r
+        result.append(months[MonthFromTime(date)]);\r
+        if (year < 0)\r
+            result.append(" -");\r
+        else\r
+            result.append(' ');\r
+        int i;\r
+        for (i = yearStr.length(); i < 4; i++)\r
+            result.append('0');\r
+        result.append(yearStr);\r
+\r
+        if (hourStr.length() == 1)\r
+            result.append(" 0");\r
+        else\r
+            result.append(' ');\r
+        result.append(hourStr);\r
+        if (minStr.length() == 1)\r
+            result.append(":0");\r
+        else\r
+            result.append(':');\r
+        result.append(minStr);\r
+        if (secStr.length() == 1)\r
+            result.append(":0");\r
+        else\r
+            result.append(':');\r
+        result.append(secStr);\r
+\r
+        result.append(" GMT");\r
+        return result.toString();\r
+    }\r
+\r
+    private static double jsFunction_getYear(Context cx, double date) {\r
+\r
+        int result = YearFromTime(LocalTime(date));\r
+\r
+        if (cx.hasFeature(Context.FEATURE_NON_ECMA_GET_YEAR)) {\r
+            if (result >= 1900 && result < 2000) {\r
+                result -= 1900;\r
+            }\r
+        } \r
+        else {\r
+            result -= 1900;\r
+        }\r
+        return result;\r
+    }\r
+\r
+    private static double jsFunction_getTimezoneOffset(double date) {\r
+        return (date - LocalTime(date)) / msPerMinute;\r
+    }\r
+\r
+    public double jsFunction_setTime(double time) {\r
+        this.date = TimeClip(time);\r
+        return this.date;\r
+    }\r
+\r
+    private double makeTime(Object[] args, int maxargs, boolean local) {\r
+        int i;\r
+        double conv[] = new double[4];\r
+        double hour, min, sec, msec;\r
+        double lorutime; /* Local or UTC version of date */\r
+\r
+        double time;\r
+        double result;\r
+\r
+        double date = this.date;\r
+\r
+        /* just return NaN if the date is already NaN */\r
+        if (date != date)\r
+            return date;\r
+\r
+        /* Satisfy the ECMA rule that if a function is called with\r
+         * fewer arguments than the specified formal arguments, the\r
+         * remaining arguments are set to undefined.  Seems like all\r
+         * the Date.setWhatever functions in ECMA are only varargs\r
+         * beyond the first argument; this should be set to undefined\r
+         * if it's not given.  This means that "d = new Date();\r
+         * d.setMilliseconds()" returns NaN.  Blech.\r
+         */\r
+        if (args.length == 0)\r
+            args = ScriptRuntime.padArguments(args, 1);\r
+\r
+        for (i = 0; i < args.length && i < maxargs; i++) {\r
+            conv[i] = ScriptRuntime.toNumber(args[i]);\r
+\r
+            // limit checks that happen in MakeTime in ECMA.\r
+            if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {\r
+                this.date = ScriptRuntime.NaN;\r
+                return this.date;\r
+            }\r
+            conv[i] = ScriptRuntime.toInteger(conv[i]);\r
+        }\r
+\r
+        if (local)\r
+            lorutime = LocalTime(date);\r
+        else\r
+            lorutime = date;\r
+\r
+        i = 0;\r
+        int stop = args.length;\r
+\r
+        if (maxargs >= 4 && i < stop)\r
+            hour = conv[i++];\r
+        else\r
+            hour = HourFromTime(lorutime);\r
+\r
+        if (maxargs >= 3 && i < stop)\r
+            min = conv[i++];\r
+        else\r
+            min = MinFromTime(lorutime);\r
+\r
+        if (maxargs >= 2 && i < stop)\r
+            sec = conv[i++];\r
+        else\r
+            sec = SecFromTime(lorutime);\r
+\r
+        if (maxargs >= 1 && i < stop)\r
+            msec = conv[i++];\r
+        else\r
+            msec = msFromTime(lorutime);\r
+\r
+        time = MakeTime(hour, min, sec, msec);\r
+        result = MakeDate(Day(lorutime), time);\r
+\r
+        if (local)\r
+            result = internalUTC(result);\r
+        date = TimeClip(result);\r
+\r
+        this.date = date;\r
+        return date;\r
+    }\r
+\r
+    private double jsFunction_setHours(Object[] args) {\r
+        return makeTime(args, 4, true);\r
+    }\r
+\r
+    private double jsFunction_setUTCHours(Object[] args) {\r
+        return makeTime(args, 4, false);\r
+    }\r
+\r
+    private double makeDate(Object[] args, int maxargs, boolean local) {\r
+        int i;\r
+        double conv[] = new double[3];\r
+        double year, month, day;\r
+        double lorutime; /* local or UTC version of date */\r
+        double result;\r
+\r
+        double date = this.date;\r
+\r
+        /* See arg padding comment in makeTime.*/\r
+        if (args.length == 0)\r
+            args = ScriptRuntime.padArguments(args, 1);\r
+\r
+        for (i = 0; i < args.length && i < maxargs; i++) {\r
+            conv[i] = ScriptRuntime.toNumber(args[i]);\r
+\r
+            // limit checks that happen in MakeDate in ECMA.\r
+            if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {\r
+                this.date = ScriptRuntime.NaN;\r
+                return this.date;\r
+            }\r
+            conv[i] = ScriptRuntime.toInteger(conv[i]);\r
+        }\r
+\r
+        /* return NaN if date is NaN and we're not setting the year,\r
+         * If we are, use 0 as the time. */\r
+        if (date != date) {\r
+            if (args.length < 3) {\r
+                return ScriptRuntime.NaN;\r
+            } else {\r
+                lorutime = 0;\r
+            }\r
+        } else {\r
+            if (local)\r
+                lorutime = LocalTime(date);\r
+            else\r
+                lorutime = date;\r
+        }\r
+\r
+        i = 0;\r
+        int stop = args.length;\r
+\r
+        if (maxargs >= 3 && i < stop)\r
+            year = conv[i++];\r
+        else\r
+            year = YearFromTime(lorutime);\r
+\r
+        if (maxargs >= 2 && i < stop)\r
+            month = conv[i++];\r
+        else\r
+            month = MonthFromTime(lorutime);\r
+\r
+        if (maxargs >= 1 && i < stop)\r
+            day = conv[i++];\r
+        else\r
+            day = DateFromTime(lorutime);\r
+\r
+        day = MakeDay(year, month, day); /* day within year */\r
+        result = MakeDate(day, TimeWithinDay(lorutime));\r
+\r
+        if (local)\r
+            result = internalUTC(result);\r
+\r
+        date = TimeClip(result);\r
+\r
+        this.date = date;\r
+        return date;\r
+    }\r
+\r
+    private double jsFunction_setYear(double year) {\r
+        double day, result;\r
+        if (year != year || Double.isInfinite(year)) {\r
+            this.date = ScriptRuntime.NaN;\r
+            return this.date;\r
+        }\r
+\r
+        if (this.date != this.date) {\r
+            this.date = 0;\r
+        } else {\r
+            this.date = LocalTime(this.date);\r
+        }\r
+\r
+        if (year >= 0 && year <= 99)\r
+            year += 1900;\r
+\r
+        day = MakeDay(year, MonthFromTime(this.date), DateFromTime(this.date));\r
+        result = MakeDate(day, TimeWithinDay(this.date));\r
+        result = internalUTC(result);\r
+\r
+        this.date = TimeClip(result);\r
+        return this.date;\r
+    }\r
+\r
+    protected String getIdName(int id) {\r
+        if (prototypeFlag) {\r
+            switch (id) {\r
+                case ConstructorId_UTC:     return "UTC";\r
+                case ConstructorId_parse:   return "parse";\r
+                case Id_constructor:        return "constructor"; \r
+                case Id_toString:           return "toString";\r
+                case Id_toTimeString:       return "toTimeString";\r
+                case Id_toDateString:       return "toDateString";\r
+                case Id_toLocaleString:     return "toLocaleString";\r
+                case Id_toLocaleTimeString: return "toLocaleTimeString";\r
+                case Id_toLocaleDateString: return "toLocaleDateString";\r
+                case Id_toUTCString:        return "toUTCString";\r
+                case Id_valueOf:            return "valueOf";\r
+                case Id_getTime:            return "getTime";\r
+                case Id_getYear:            return "getYear";\r
+                case Id_getFullYear:        return "getFullYear";\r
+                case Id_getUTCFullYear:     return "getUTCFullYear";\r
+                case Id_getMonth:           return "getMonth";\r
+                case Id_getUTCMonth:        return "getUTCMonth";\r
+                case Id_getDate:            return "getDate";\r
+                case Id_getUTCDate:         return "getUTCDate";\r
+                case Id_getDay:             return "getDay";\r
+                case Id_getUTCDay:          return "getUTCDay";\r
+                case Id_getHours:           return "getHours";\r
+                case Id_getUTCHours:        return "getUTCHours";\r
+                case Id_getMinutes:         return "getMinutes";\r
+                case Id_getUTCMinutes:      return "getUTCMinutes";\r
+                case Id_getSeconds:         return "getSeconds";\r
+                case Id_getUTCSeconds:      return "getUTCSeconds";\r
+                case Id_getMilliseconds:    return "getMilliseconds";\r
+                case Id_getUTCMilliseconds: return "getUTCMilliseconds";\r
+                case Id_getTimezoneOffset:  return "getTimezoneOffset";\r
+                case Id_setTime:            return "setTime";\r
+                case Id_setMilliseconds:    return "setMilliseconds";\r
+                case Id_setUTCMilliseconds: return "setUTCMilliseconds";\r
+                case Id_setSeconds:         return "setSeconds";\r
+                case Id_setUTCSeconds:      return "setUTCSeconds";\r
+                case Id_setMinutes:         return "setMinutes";\r
+                case Id_setUTCMinutes:      return "setUTCMinutes";\r
+                case Id_setHours:           return "setHours";\r
+                case Id_setUTCHours:        return "setUTCHours";\r
+                case Id_setDate:            return "setDate";\r
+                case Id_setUTCDate:         return "setUTCDate";\r
+                case Id_setMonth:           return "setMonth";\r
+                case Id_setUTCMonth:        return "setUTCMonth";\r
+                case Id_setFullYear:        return "setFullYear";\r
+                case Id_setUTCFullYear:     return "setUTCFullYear";\r
+                case Id_setYear:            return "setYear";\r
+            }\r
+        }\r
+        return null;        \r
+    }\r
+\r
+// #string_id_map#\r
+\r
+    protected int mapNameToId(String s) {\r
+        if (!prototypeFlag) { return 0; }\r
+        int id;\r
+// #generated# Last update: 2001-04-22 23:46:59 CEST\r
+        L0: { id = 0; String X = null; int c;\r
+            L: switch (s.length()) {\r
+            case 6: X="getDay";id=Id_getDay; break L;\r
+            case 7: switch (s.charAt(3)) {\r
+                case 'D': c=s.charAt(0);\r
+                    if (c=='g') { X="getDate";id=Id_getDate; }\r
+                    else if (c=='s') { X="setDate";id=Id_setDate; }\r
+                    break L;\r
+                case 'T': c=s.charAt(0);\r
+                    if (c=='g') { X="getTime";id=Id_getTime; }\r
+                    else if (c=='s') { X="setTime";id=Id_setTime; }\r
+                    break L;\r
+                case 'Y': c=s.charAt(0);\r
+                    if (c=='g') { X="getYear";id=Id_getYear; }\r
+                    else if (c=='s') { X="setYear";id=Id_setYear; }\r
+                    break L;\r
+                case 'u': X="valueOf";id=Id_valueOf; break L;\r
+                } break L;\r
+            case 8: c=s.charAt(0);\r
+                if (c=='g') {\r
+                    c=s.charAt(7);\r
+                    if (c=='h') { X="getMonth";id=Id_getMonth; }\r
+                    else if (c=='s') { X="getHours";id=Id_getHours; }\r
+                }\r
+                else if (c=='s') {\r
+                    c=s.charAt(7);\r
+                    if (c=='h') { X="setMonth";id=Id_setMonth; }\r
+                    else if (c=='s') { X="setHours";id=Id_setHours; }\r
+                }\r
+                else if (c=='t') { X="toString";id=Id_toString; }\r
+                break L;\r
+            case 9: X="getUTCDay";id=Id_getUTCDay; break L;\r
+            case 10: c=s.charAt(3);\r
+                if (c=='M') {\r
+                    c=s.charAt(0);\r
+                    if (c=='g') { X="getMinutes";id=Id_getMinutes; }\r
+                    else if (c=='s') { X="setMinutes";id=Id_setMinutes; }\r
+                }\r
+                else if (c=='S') {\r
+                    c=s.charAt(0);\r
+                    if (c=='g') { X="getSeconds";id=Id_getSeconds; }\r
+                    else if (c=='s') { X="setSeconds";id=Id_setSeconds; }\r
+                }\r
+                else if (c=='U') {\r
+                    c=s.charAt(0);\r
+                    if (c=='g') { X="getUTCDate";id=Id_getUTCDate; }\r
+                    else if (c=='s') { X="setUTCDate";id=Id_setUTCDate; }\r
+                }\r
+                break L;\r
+            case 11: switch (s.charAt(3)) {\r
+                case 'F': c=s.charAt(0);\r
+                    if (c=='g') { X="getFullYear";id=Id_getFullYear; }\r
+                    else if (c=='s') { X="setFullYear";id=Id_setFullYear; }\r
+                    break L;\r
+                case 'M': X="toGMTString";id=Id_toGMTString; break L;\r
+                case 'T': X="toUTCString";id=Id_toUTCString; break L;\r
+                case 'U': c=s.charAt(0);\r
+                    if (c=='g') {\r
+                        c=s.charAt(9);\r
+                        if (c=='r') { X="getUTCHours";id=Id_getUTCHours; }\r
+                        else if (c=='t') { X="getUTCMonth";id=Id_getUTCMonth; }\r
+                    }\r
+                    else if (c=='s') {\r
+                        c=s.charAt(9);\r
+                        if (c=='r') { X="setUTCHours";id=Id_setUTCHours; }\r
+                        else if (c=='t') { X="setUTCMonth";id=Id_setUTCMonth; }\r
+                    }\r
+                    break L;\r
+                case 's': X="constructor";id=Id_constructor; break L;\r
+                } break L;\r
+            case 12: c=s.charAt(2);\r
+                if (c=='D') { X="toDateString";id=Id_toDateString; }\r
+                else if (c=='T') { X="toTimeString";id=Id_toTimeString; }\r
+                break L;\r
+            case 13: c=s.charAt(0);\r
+                if (c=='g') {\r
+                    c=s.charAt(6);\r
+                    if (c=='M') { X="getUTCMinutes";id=Id_getUTCMinutes; }\r
+                    else if (c=='S') { X="getUTCSeconds";id=Id_getUTCSeconds; }\r
+                }\r
+                else if (c=='s') {\r
+                    c=s.charAt(6);\r
+                    if (c=='M') { X="setUTCMinutes";id=Id_setUTCMinutes; }\r
+                    else if (c=='S') { X="setUTCSeconds";id=Id_setUTCSeconds; }\r
+                }\r
+                break L;\r
+            case 14: c=s.charAt(0);\r
+                if (c=='g') { X="getUTCFullYear";id=Id_getUTCFullYear; }\r
+                else if (c=='s') { X="setUTCFullYear";id=Id_setUTCFullYear; }\r
+                else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; }\r
+                break L;\r
+            case 15: c=s.charAt(0);\r
+                if (c=='g') { X="getMilliseconds";id=Id_getMilliseconds; }\r
+                else if (c=='s') { X="setMilliseconds";id=Id_setMilliseconds; }\r
+                break L;\r
+            case 17: X="getTimezoneOffset";id=Id_getTimezoneOffset; break L;\r
+            case 18: c=s.charAt(0);\r
+                if (c=='g') { X="getUTCMilliseconds";id=Id_getUTCMilliseconds; }\r
+                else if (c=='s') { X="setUTCMilliseconds";id=Id_setUTCMilliseconds; }\r
+                else if (c=='t') {\r
+                    c=s.charAt(8);\r
+                    if (c=='D') { X="toLocaleDateString";id=Id_toLocaleDateString; }\r
+                    else if (c=='T') { X="toLocaleTimeString";id=Id_toLocaleTimeString; }\r
+                }\r
+                break L;\r
+            }\r
+            if (X!=null && X!=s && !X.equals(s)) id = 0;\r
+        }\r
+// #/generated#\r
+        return id;\r
+    }\r
+\r
+    private static final int\r
+        ConstructorId_UTC       = -2,\r
+        ConstructorId_parse     = -1,\r
+\r
+        Id_constructor          =  1,\r
+        Id_toString             =  2,\r
+        Id_toTimeString         =  3,\r
+        Id_toDateString         =  4,\r
+        Id_toLocaleString       =  5,\r
+        Id_toLocaleTimeString   =  6,\r
+        Id_toLocaleDateString   =  7,\r
+        Id_toUTCString          =  8,\r
+        Id_valueOf              =  9,\r
+        Id_getTime              = 10,\r
+        Id_getYear              = 11,\r
+        Id_getFullYear          = 12,\r
+        Id_getUTCFullYear       = 13,\r
+        Id_getMonth             = 14,\r
+        Id_getUTCMonth          = 15,\r
+        Id_getDate              = 16,\r
+        Id_getUTCDate           = 17,\r
+        Id_getDay               = 18,\r
+        Id_getUTCDay            = 19,\r
+        Id_getHours             = 20,\r
+        Id_getUTCHours          = 21,\r
+        Id_getMinutes           = 22,\r
+        Id_getUTCMinutes        = 23,\r
+        Id_getSeconds           = 24,\r
+        Id_getUTCSeconds        = 25,\r
+        Id_getMilliseconds      = 26,\r
+        Id_getUTCMilliseconds   = 27,\r
+        Id_getTimezoneOffset    = 28,\r
+        Id_setTime              = 29,\r
+        Id_setMilliseconds      = 30,\r
+        Id_setUTCMilliseconds   = 31,\r
+        Id_setSeconds           = 32,\r
+        Id_setUTCSeconds        = 33,\r
+        Id_setMinutes           = 34,\r
+        Id_setUTCMinutes        = 35,\r
+        Id_setHours             = 36,\r
+        Id_setUTCHours          = 37,\r
+        Id_setDate              = 38,\r
+        Id_setUTCDate           = 39,\r
+        Id_setMonth             = 40,\r
+        Id_setUTCMonth          = 41,\r
+        Id_setFullYear          = 42,\r
+        Id_setUTCFullYear       = 43,\r
+        Id_setYear              = 44,\r
+\r
+        MAX_PROTOTYPE_ID        = 44;\r
+\r
+    private static final int\r
+        Id_toGMTString  =  Id_toUTCString; // Alias, see Ecma B.2.6\r
+// #/string_id_map#\r
+\r
+    /* cached values */\r
+    private static java.util.TimeZone thisTimeZone;\r
+    private static double LocalTZA;\r
+    private static java.text.DateFormat timeZoneFormatter;\r
+    private static java.text.DateFormat localeDateTimeFormatter;\r
+    private static java.text.DateFormat localeDateFormatter;\r
+    private static java.text.DateFormat localeTimeFormatter;\r
+\r
+    private double date;\r
+\r
+    private boolean prototypeFlag;\r
+}\r
+\r
+\r