2003/09/26 07:09:55
[org.ibex.core.git] / src / org / xwt / js / Date.java
1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * The contents of this file are subject to the Netscape Public
4  * License Version 1.1 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of
6  * the License at http://www.mozilla.org/NPL/
7  *
8  * Software distributed under the License is distributed on an "AS
9  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
10  * implied. See the License for the specific language governing
11  * rights and limitations under the License.
12  *
13  * The Original Code is Rhino code, released
14  * May 6, 1999.
15  *
16  * The Initial Developer of the Original Code is Netscape
17  * Communications Corporation.  Portions created by Netscape are
18  * Copyright (C) 1997-1999 Netscape Communications Corporation. All
19  * Rights Reserved.
20  *
21  * Contributor(s):
22  * Norris Boyd
23  * Mike McCabe
24  *
25  * Alternatively, the contents of this file may be used under the
26  * terms of the GNU Public License (the "GPL"), in which case the
27  * provisions of the GPL are applicable instead of those above.
28  * If you wish to allow use of your version of this file only
29  * under the terms of the GPL and not to allow others to use your
30  * version of this file under the NPL, indicate your decision by
31  * deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL.  If you do not delete
33  * the provisions above, a recipient may use your version of this
34  * file under either the NPL or the GPL.
35  */
36
37 package org.xwt.js;
38
39 import java.util.TimeZone;
40 import java.util.Locale;
41 import java.text.NumberFormat;
42 import java.text.DateFormat;
43 import java.text.SimpleDateFormat;
44
45 /**
46  * This class implements the Date native object.
47  * See ECMA 15.9.
48  * @author Mike McCabe
49  */
50 public class Date extends JS.Obj {
51
52     public Date() {
53         if (thisTimeZone == null) {
54             // j.u.TimeZone is synchronized, so setting class statics from it
55             // should be OK.
56             thisTimeZone = java.util.TimeZone.getDefault();
57             LocalTZA = thisTimeZone.getRawOffset();
58         }
59     }
60
61     public String coerceToString() { return date_format(date, FORMATSPEC_FULL); }
62
63     public Object callMethod(Object name, JS.Array args_, boolean checkOnly) {
64         Object[] args = new Object[args_.length()];
65         for(int i=0; i<args.length; i++) args[i] = args_.elementAt(i);
66
67         if (name.equals(getIdName(ConstructorId_UTC))) { 
68             if (checkOnly) return Boolean.TRUE;
69             return new Double(jsStaticFunction_UTC(args));
70             
71         } else if (name.equals(getIdName(ConstructorId_parse))) { 
72             if (checkOnly) return Boolean.TRUE;
73             return new Double(jsStaticFunction_parse(args[0].toString()));
74             
75         } else if (name.equals(getIdName(Id_constructor))) {
76             if (checkOnly) return Boolean.TRUE;
77             return new Date(args_);
78             
79         } else if (name.equals(getIdName(Id_toString))) {
80             if (checkOnly) return Boolean.TRUE;
81             double t = date;
82             return date_format(t, FORMATSPEC_FULL);
83
84         } else if (name.equals(getIdName(Id_toTimeString))) {
85             if (checkOnly) return Boolean.TRUE;
86             double t = date;
87             return date_format(t, FORMATSPEC_TIME);
88
89         } else if (name.equals(getIdName(Id_toDateString))) {
90             if (checkOnly) return Boolean.TRUE;
91             double t = date;
92             return date_format(t, FORMATSPEC_DATE);
93
94         } else if (name.equals(getIdName(Id_toLocaleString))) {
95             if (checkOnly) return Boolean.TRUE;
96             double t = date;
97             return jsFunction_toLocaleString(t);
98
99         } else if (name.equals(getIdName(Id_toLocaleTimeString))) {
100             if (checkOnly) return Boolean.TRUE;
101             double t = date;
102             return jsFunction_toLocaleTimeString(t);
103
104         } else if (name.equals(getIdName(Id_toLocaleDateString))) {
105             if (checkOnly) return Boolean.TRUE;
106             double t = date;
107             return jsFunction_toLocaleDateString(t);
108
109         } else if (name.equals(getIdName(Id_toUTCString))) {
110             if (checkOnly) return Boolean.TRUE;
111             double t = date;
112             return jsFunction_toUTCString(t);
113
114         } else if (name.equals(getIdName(Id_valueOf))) { 
115             if (checkOnly) return Boolean.TRUE;
116             return new Double(this.date);
117
118         } else if (name.equals(getIdName(Id_getTime))) { 
119             if (checkOnly) return Boolean.TRUE;
120             return new Double(this.date);
121
122         } else if (name.equals(getIdName(Id_getYear))) {
123             if (checkOnly) return Boolean.TRUE;
124             double t = date;
125             t = jsFunction_getYear(t);
126             return new Double(t);
127
128         } else if (name.equals(getIdName(Id_getFullYear))) {
129             if (checkOnly) return Boolean.TRUE;
130             double t = date;
131             t = YearFromTime(LocalTime(t));
132             return new Double(t);
133
134         } else if (name.equals(getIdName(Id_getUTCFullYear))) {
135             if (checkOnly) return Boolean.TRUE;
136             double t = date;
137             t = YearFromTime(t);
138             return new Double(t);
139
140         } else if (name.equals(getIdName(Id_getMonth))) {
141             if (checkOnly) return Boolean.TRUE;
142             double t = date;
143             t = MonthFromTime(LocalTime(t));
144             return new Double(t);
145                 
146         } else if (name.equals(getIdName(Id_getUTCMonth))) {
147             if (checkOnly) return Boolean.TRUE;
148             double t = date;
149             t = MonthFromTime(t);
150             return new Double(t);
151
152         } else if (name.equals(getIdName(Id_getDate))) {
153             if (checkOnly) return Boolean.TRUE;
154             double t = date;
155             t = DateFromTime(LocalTime(t));
156             return new Double(t);
157
158         } else if (name.equals(getIdName(Id_getUTCDate))) {
159             if (checkOnly) return Boolean.TRUE;
160             double t = date;
161             t = DateFromTime(t);
162             return new Double(t);
163
164         } else if (name.equals(getIdName(Id_getDay))) {
165             if (checkOnly) return Boolean.TRUE;
166             double t = date;
167             t = WeekDay(LocalTime(t));
168             return new Double(t);
169
170         } else if (name.equals(getIdName(Id_getUTCDay))) {
171             if (checkOnly) return Boolean.TRUE;
172             double t = date;
173             t = WeekDay(t);
174             return new Double(t);
175
176         } else if (name.equals(getIdName(Id_getHours))) {
177             if (checkOnly) return Boolean.TRUE;
178             double t = date;
179             t = HourFromTime(LocalTime(t));
180             return new Double(t);
181
182         } else if (name.equals(getIdName(Id_getUTCHours))) {
183             if (checkOnly) return Boolean.TRUE;
184             double t = date;
185             t = HourFromTime(t);
186             return new Double(t);
187
188         } else if (name.equals(getIdName(Id_getMinutes))) {
189             if (checkOnly) return Boolean.TRUE;
190             double t = date;
191             t = MinFromTime(LocalTime(t));
192             return new Double(t);
193
194         } else if (name.equals(getIdName(Id_getUTCMinutes))) {
195             if (checkOnly) return Boolean.TRUE;
196             double t = date;
197             t = MinFromTime(t);
198             return new Double(t);
199
200         } else if (name.equals(getIdName(Id_getSeconds))) {
201             if (checkOnly) return Boolean.TRUE;
202             double t = date;
203             t = SecFromTime(LocalTime(t));
204             return new Double(t);
205
206         } else if (name.equals(getIdName(Id_getUTCSeconds))) {
207             if (checkOnly) return Boolean.TRUE;
208             double t = date;
209             t = SecFromTime(t);
210             return new Double(t);
211                 
212         } else if (name.equals(getIdName(Id_getMilliseconds))) {
213             if (checkOnly) return Boolean.TRUE;
214             double t = date;
215             t = msFromTime(LocalTime(t));
216             return new Double(t);
217
218         } else if (name.equals(getIdName(Id_getUTCMilliseconds))) {
219             if (checkOnly) return Boolean.TRUE;
220             double t = date;
221             t = msFromTime(t);
222             return new Double(t);
223
224         } else if (name.equals(getIdName(Id_getTimezoneOffset))) {
225             if (checkOnly) return Boolean.TRUE;
226             double t = date;
227             t = jsFunction_getTimezoneOffset(t);
228             return new Double(t);
229
230         } else if (name.equals(getIdName(Id_setTime))) { 
231             if (checkOnly) return Boolean.TRUE;
232             return new Double(this.jsFunction_setTime(_toNumber(args, 0)));
233
234         } else if (name.equals(getIdName(Id_setMilliseconds))) { 
235             if (checkOnly) return Boolean.TRUE;
236             return new Double(this.
237                                makeTime(args, 1, true));
238
239         } else if (name.equals(getIdName(Id_setUTCMilliseconds))) { 
240             if (checkOnly) return Boolean.TRUE;
241             return new Double(this.
242                                makeTime(args, 1, false));
243
244         } else if (name.equals(getIdName(Id_setSeconds))) { 
245             if (checkOnly) return Boolean.TRUE;
246             return new Double(this.
247                                makeTime(args, 2, true));
248
249         } else if (name.equals(getIdName(Id_setUTCSeconds))) { 
250             if (checkOnly) return Boolean.TRUE;
251             return new Double(this.
252                                makeTime(args, 2, false));
253
254         } else if (name.equals(getIdName(Id_setMinutes))) { 
255             if (checkOnly) return Boolean.TRUE;
256             return new Double(this.
257                                makeTime(args, 3, true));
258
259         } else if (name.equals(getIdName(Id_setUTCMinutes))) { 
260             if (checkOnly) return Boolean.TRUE;
261             return new Double(this.
262                                makeTime(args, 3, false));
263
264         } else if (name.equals(getIdName(Id_setHours))) { 
265             if (checkOnly) return Boolean.TRUE;
266             return new Double(this.
267                                makeTime(args, 4, true));
268
269         } else if (name.equals(getIdName(Id_setUTCHours))) { 
270             if (checkOnly) return Boolean.TRUE;
271             return new Double(this.
272                                makeTime(args, 4, false));
273
274         } else if (name.equals(getIdName(Id_setDate))) { 
275             if (checkOnly) return Boolean.TRUE;
276             return new Double(this.
277                                makeDate(args, 1, true));
278
279         } else if (name.equals(getIdName(Id_setUTCDate))) { 
280             if (checkOnly) return Boolean.TRUE;
281             return new Double(this.
282                                makeDate(args, 1, false));
283
284         } else if (name.equals(getIdName(Id_setMonth))) { 
285             if (checkOnly) return Boolean.TRUE;
286             return new Double(this.
287                                makeDate(args, 2, true));
288
289         } else if (name.equals(getIdName(Id_setUTCMonth))) { 
290             if (checkOnly) return Boolean.TRUE;
291             return new Double(this.
292                                makeDate(args, 2, false));
293
294         } else if (name.equals(getIdName(Id_setFullYear))) { 
295             if (checkOnly) return Boolean.TRUE;
296             return new Double(this.
297                                makeDate(args, 3, true));
298
299         } else if (name.equals(getIdName(Id_setUTCFullYear))) { 
300             if (checkOnly) return Boolean.TRUE;
301             return new Double(this.
302                                makeDate(args, 3, false));
303
304         } else if (name.equals(getIdName(Id_setYear))) { 
305             if (checkOnly) return Boolean.TRUE;
306             return new Double(this.
307                                jsFunction_setYear(_toNumber(args, 0)));
308         }
309         if (checkOnly) return Boolean.FALSE;
310         return null;
311     }
312
313     /* ECMA helper functions */
314
315     private static final double HalfTimeDomain = 8.64e15;
316     private static final double HoursPerDay    = 24.0;
317     private static final double MinutesPerHour = 60.0;
318     private static final double SecondsPerMinute = 60.0;
319     private static final double msPerSecond    = 1000.0;
320     private static final double MinutesPerDay  = (HoursPerDay * MinutesPerHour);
321     private static final double SecondsPerDay  = (MinutesPerDay * SecondsPerMinute);
322     private static final double SecondsPerHour = (MinutesPerHour * SecondsPerMinute);
323     private static final double msPerDay       = (SecondsPerDay * msPerSecond);
324     private static final double msPerHour      = (SecondsPerHour * msPerSecond);
325     private static final double msPerMinute    = (SecondsPerMinute * msPerSecond);
326
327     private static double Day(double t) {
328         return java.lang.Math.floor(t / msPerDay);
329     }
330
331     private static double TimeWithinDay(double t) {
332         double result;
333         result = t % msPerDay;
334         if (result < 0)
335             result += msPerDay;
336         return result;
337     }
338
339     private static int DaysInYear(int y) {
340         if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
341             return 366;
342         else
343             return 365;
344     }
345
346
347     /* math here has to be f.p, because we need
348      *  floor((1968 - 1969) / 4) == -1
349      */
350     private static double DayFromYear(double y) {
351         return ((365 * ((y)-1970) + java.lang.Math.floor(((y)-1969)/4.0)
352                  - java.lang.Math.floor(((y)-1901)/100.0) + java.lang.Math.floor(((y)-1601)/400.0)));
353     }
354
355     private static double TimeFromYear(double y) {
356         return DayFromYear(y) * msPerDay;
357     }
358
359     private static int YearFromTime(double t) {
360         int lo = (int) java.lang.Math.floor((t / msPerDay) / 366) + 1970;
361         int hi = (int) java.lang.Math.floor((t / msPerDay) / 365) + 1970;
362         int mid;
363
364         /* above doesn't work for negative dates... */
365         if (hi < lo) {
366             int temp = lo;
367             lo = hi;
368             hi = temp;
369         }
370
371         /* Use a simple binary search algorithm to find the right
372            year.  This seems like brute force... but the computation
373            of hi and lo years above lands within one year of the
374            correct answer for years within a thousand years of
375            1970; the loop below only requires six iterations
376            for year 270000. */
377         while (hi > lo) {
378             mid = (hi + lo) / 2;
379             if (TimeFromYear(mid) > t) {
380                 hi = mid - 1;
381             } else {
382                 if (TimeFromYear(mid) <= t) {
383                     int temp = mid + 1;
384                     if (TimeFromYear(temp) > t) {
385                         return mid;
386                     }
387                     lo = mid + 1;
388                 }
389             }
390         }
391         return lo;
392     }
393
394     private static boolean InLeapYear(double t) {
395         return DaysInYear(YearFromTime(t)) == 366;
396     }
397
398     private static int DayWithinYear(double t) {
399         int year = YearFromTime(t);
400         return (int) (Day(t) - DayFromYear(year));
401     }
402     /*
403      * The following array contains the day of year for the first day of
404      * each month, where index 0 is January, and day 0 is January 1.
405      */
406
407     private static double DayFromMonth(int m, boolean leap) {
408         int day = m * 30;
409
410         if (m >= 7) { day += m / 2 - 1; }
411         else if (m >= 2) { day += (m - 1) / 2 - 1; }
412         else { day += m; }
413
414         if (leap && m >= 2) { ++day; }
415
416         return day;
417     }
418
419     private static int MonthFromTime(double t) {
420         int d, step;
421
422         d = DayWithinYear(t);
423
424         if (d < (step = 31))
425             return 0;
426
427         // Originally coded as step += (InLeapYear(t) ? 29 : 28);
428         // but some jits always returned 28!
429         if (InLeapYear(t))
430             step += 29;
431         else
432             step += 28;
433
434         if (d < step)
435             return 1;
436         if (d < (step += 31))
437             return 2;
438         if (d < (step += 30))
439             return 3;
440         if (d < (step += 31))
441             return 4;
442         if (d < (step += 30))
443             return 5;
444         if (d < (step += 31))
445             return 6;
446         if (d < (step += 31))
447             return 7;
448         if (d < (step += 30))
449             return 8;
450         if (d < (step += 31))
451             return 9;
452         if (d < (step += 30))
453             return 10;
454         return 11;
455     }
456
457     private static int DateFromTime(double t) {
458         int d, step, next;
459
460         d = DayWithinYear(t);
461         if (d <= (next = 30))
462             return d + 1;
463         step = next;
464
465         // Originally coded as next += (InLeapYear(t) ? 29 : 28);
466         // but some jits always returned 28!
467         if (InLeapYear(t))
468             next += 29;
469         else
470             next += 28;
471
472         if (d <= next)
473             return d - step;
474         step = next;
475         if (d <= (next += 31))
476             return d - step;
477         step = next;
478         if (d <= (next += 30))
479             return d - step;
480         step = next;
481         if (d <= (next += 31))
482             return d - step;
483         step = next;
484         if (d <= (next += 30))
485             return d - step;
486         step = next;
487         if (d <= (next += 31))
488             return d - step;
489         step = next;
490         if (d <= (next += 31))
491             return d - step;
492         step = next;
493         if (d <= (next += 30))
494             return d - step;
495         step = next;
496         if (d <= (next += 31))
497             return d - step;
498         step = next;
499         if (d <= (next += 30))
500             return d - step;
501         step = next;
502
503         return d - step;
504     }
505
506     private static int WeekDay(double t) {
507         double result;
508         result = Day(t) + 4;
509         result = result % 7;
510         if (result < 0)
511             result += 7;
512         return (int) result;
513     }
514
515     private static double Now() {
516         return (double) System.currentTimeMillis();
517     }
518
519     /* Should be possible to determine the need for this dynamically
520      * if we go with the workaround... I'm not using it now, because I
521      * can't think of any clean way to make toLocaleString() and the
522      * time zone (comment) in toString match the generated string
523      * values.  Currently it's wrong-but-consistent in all but the
524      * most recent betas of the JRE - seems to work in 1.1.7.
525      */
526     private final static boolean TZO_WORKAROUND = false;
527     private static double DaylightSavingTA(double t) {
528         if (!TZO_WORKAROUND) {
529             java.util.Date date = new java.util.Date((long) t);
530             if (thisTimeZone.inDaylightTime(date))
531                 return msPerHour;
532             else
533                 return 0;
534         } else {
535             /* Use getOffset if inDaylightTime() is broken, because it
536              * seems to work acceptably.  We don't switch over to it
537              * entirely, because it requires (expensive) exploded date arguments,
538              * and the api makes it impossible to handle dst
539              * changeovers cleanly.
540              */
541
542             // Hardcode the assumption that the changeover always
543             // happens at 2:00 AM:
544             t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);
545
546             int year = YearFromTime(t);
547             double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0,
548                                                    year,
549                                                    MonthFromTime(t),
550                                                    DateFromTime(t),
551                                                    WeekDay(t),
552                                                    (int)TimeWithinDay(t));
553
554             if ((offset - LocalTZA) != 0)
555                 return msPerHour;
556             else
557                 return 0;
558             //         return offset - LocalTZA;
559         }
560     }
561
562     private static double LocalTime(double t) {
563         return t + LocalTZA + DaylightSavingTA(t);
564     }
565
566     public static double internalUTC(double t) {
567         return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
568     }
569
570     private static int HourFromTime(double t) {
571         double result;
572         result = java.lang.Math.floor(t / msPerHour) % HoursPerDay;
573         if (result < 0)
574             result += HoursPerDay;
575         return (int) result;
576     }
577
578     private static int MinFromTime(double t) {
579         double result;
580         result = java.lang.Math.floor(t / msPerMinute) % MinutesPerHour;
581         if (result < 0)
582             result += MinutesPerHour;
583         return (int) result;
584     }
585
586     private static int SecFromTime(double t) {
587         double result;
588         result = java.lang.Math.floor(t / msPerSecond) % SecondsPerMinute;
589         if (result < 0)
590             result += SecondsPerMinute;
591         return (int) result;
592     }
593
594     private static int msFromTime(double t) {
595         double result;
596         result =  t % msPerSecond;
597         if (result < 0)
598             result += msPerSecond;
599         return (int) result;
600     }
601
602     private static double MakeTime(double hour, double min,
603                                    double sec, double ms)
604     {
605         return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)
606             * msPerSecond + ms;
607     }
608
609     private static double MakeDay(double year, double month, double date) {
610         double result;
611         boolean leap;
612         double yearday;
613         double monthday;
614
615         year += java.lang.Math.floor(month / 12);
616
617         month = month % 12;
618         if (month < 0)
619             month += 12;
620
621         leap = (DaysInYear((int) year) == 366);
622
623         yearday = java.lang.Math.floor(TimeFromYear(year) / msPerDay);
624         monthday = DayFromMonth((int) month, leap);
625
626         result = yearday
627             + monthday
628             + date - 1;
629         return result;
630     }
631
632     private static double MakeDate(double day, double time) {
633         return day * msPerDay + time;
634     }
635
636     private static double TimeClip(double d) {
637         if (d != d ||
638             d == Double.POSITIVE_INFINITY ||
639             d == Double.NEGATIVE_INFINITY ||
640             java.lang.Math.abs(d) > HalfTimeDomain)
641         {
642             return Double.NaN;
643         }
644         if (d > 0.0)
645             return java.lang.Math.floor(d + 0.);
646         else
647             return java.lang.Math.ceil(d + 0.);
648     }
649
650     /* end of ECMA helper functions */
651
652     /* find UTC time from given date... no 1900 correction! */
653     public static double date_msecFromDate(double year, double mon,
654                                             double mday, double hour,
655                                             double min, double sec,
656                                             double msec)
657     {
658         double day;
659         double time;
660         double result;
661
662         day = MakeDay(year, mon, mday);
663         time = MakeTime(hour, min, sec, msec);
664         result = MakeDate(day, time);
665         return result;
666     }
667
668
669     private static final int MAXARGS = 7;
670     private static double jsStaticFunction_UTC(Object[] args) {
671         double array[] = new double[MAXARGS];
672         int loop;
673         double d;
674
675         for (loop = 0; loop < MAXARGS; loop++) {
676             if (loop < args.length) {
677                 d = _toNumber(args[loop]);
678                 if (d != d || Double.isInfinite(d)) {
679                     return Double.NaN;
680                 }
681                 array[loop] = toDouble(args[loop]);
682             } else {
683                 array[loop] = 0;
684             }
685         }
686
687         /* adjust 2-digit years into the 20th century */
688         if (array[0] >= 0 && array[0] <= 99)
689             array[0] += 1900;
690
691             /* if we got a 0 for 'date' (which is out of range)
692              * pretend it's a 1.  (So Date.UTC(1972, 5) works) */
693         if (array[2] < 1)
694             array[2] = 1;
695
696         d = date_msecFromDate(array[0], array[1], array[2],
697                               array[3], array[4], array[5], array[6]);
698         d = TimeClip(d);
699         return d;
700         //        return new Double(d);
701     }
702
703     /*
704      * Use ported code from jsdate.c rather than the locale-specific
705      * date-parsing code from Java, to keep js and rhino consistent.
706      * Is this the right strategy?
707      */
708
709     /* for use by date_parse */
710
711     /* replace this with byte arrays?  Cheaper? */
712     private static String wtb[] = {
713         "am", "pm",
714         "monday", "tuesday", "wednesday", "thursday", "friday",
715         "saturday", "sunday",
716         "january", "february", "march", "april", "may", "june",
717         "july", "august", "september", "october", "november", "december",
718         "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
719         "mst", "mdt", "pst", "pdt"
720         /* time zone table needs to be expanded */
721     };
722
723     private static int ttb[] = {
724         -1, -2, 0, 0, 0, 0, 0, 0, 0,     /* AM/PM */
725         2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
726         10000 + 0, 10000 + 0, 10000 + 0, /* UT/UTC */
727         10000 + 5 * 60, 10000 + 4 * 60,  /* EDT */
728         10000 + 6 * 60, 10000 + 5 * 60,
729         10000 + 7 * 60, 10000 + 6 * 60,
730         10000 + 8 * 60, 10000 + 7 * 60
731     };
732
733     /* helper for date_parse */
734     private static boolean date_regionMatches(String s1, int s1off,
735                                               String s2, int s2off,
736                                               int count)
737     {
738         boolean result = false;
739         /* return true if matches, otherwise, false */
740         int s1len = s1.length();
741         int s2len = s2.length();
742
743         while (count > 0 && s1off < s1len && s2off < s2len) {
744             if (Character.toLowerCase(s1.charAt(s1off)) !=
745                 Character.toLowerCase(s2.charAt(s2off)))
746                 break;
747             s1off++;
748             s2off++;
749             count--;
750         }
751
752         if (count == 0) {
753             result = true;
754         }
755         return result;
756     }
757
758     private static double date_parseString(String s) {
759         double msec;
760
761         int year = -1;
762         int mon = -1;
763         int mday = -1;
764         int hour = -1;
765         int min = -1;
766         int sec = -1;
767         char c = 0;
768         char si = 0;
769         int i = 0;
770         int n = -1;
771         double tzoffset = -1;
772         char prevc = 0;
773         int limit = 0;
774         boolean seenplusminus = false;
775
776         if (s == null)  // ??? Will s be null?
777             return Double.NaN;
778         limit = s.length();
779         while (i < limit) {
780             c = s.charAt(i);
781             i++;
782             if (c <= ' ' || c == ',' || c == '-') {
783                 if (i < limit) {
784                     si = s.charAt(i);
785                     if (c == '-' && '0' <= si && si <= '9') {
786                         prevc = c;
787                     }
788                 }
789                 continue;
790             }
791             if (c == '(') { /* comments) */
792                 int depth = 1;
793                 while (i < limit) {
794                     c = s.charAt(i);
795                     i++;
796                     if (c == '(')
797                         depth++;
798                     else if (c == ')')
799                         if (--depth <= 0)
800                             break;
801                 }
802                 continue;
803             }
804             if ('0' <= c && c <= '9') {
805                 n = c - '0';
806                 while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
807                     n = n * 10 + c - '0';
808                     i++;
809                 }
810
811                 /* allow TZA before the year, so
812                  * 'Wed Nov 05 21:49:11 GMT-0800 1997'
813                  * works */
814
815                 /* uses of seenplusminus allow : in TZA, so Java
816                  * no-timezone style of GMT+4:30 works
817                  */
818                 if ((prevc == '+' || prevc == '-')/*  && year>=0 */) {
819                     /* make ':' case below change tzoffset */
820                     seenplusminus = true;
821
822                     /* offset */
823                     if (n < 24)
824                         n = n * 60; /* EG. "GMT-3" */
825                     else
826                         n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
827                     if (prevc == '+')       /* plus means east of GMT */
828                         n = -n;
829                     if (tzoffset != 0 && tzoffset != -1)
830                         return Double.NaN;
831                     tzoffset = n;
832                 } else if (n >= 70  ||
833                            (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
834                     if (year >= 0)
835                         return Double.NaN;
836                     else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
837                         year = n < 100 ? n + 1900 : n;
838                     else
839                         return Double.NaN;
840                 } else if (c == ':') {
841                     if (hour < 0)
842                         hour = /*byte*/ n;
843                     else if (min < 0)
844                         min = /*byte*/ n;
845                     else
846                         return Double.NaN;
847                 } else if (c == '/') {
848                     if (mon < 0)
849                         mon = /*byte*/ n-1;
850                     else if (mday < 0)
851                         mday = /*byte*/ n;
852                     else
853                         return Double.NaN;
854                 } else if (i < limit && c != ',' && c > ' ' && c != '-') {
855                     return Double.NaN;
856                 } else if (seenplusminus && n < 60) {  /* handle GMT-3:30 */
857                     if (tzoffset < 0)
858                         tzoffset -= n;
859                     else
860                         tzoffset += n;
861                 } else if (hour >= 0 && min < 0) {
862                     min = /*byte*/ n;
863                 } else if (min >= 0 && sec < 0) {
864                     sec = /*byte*/ n;
865                 } else if (mday < 0) {
866                     mday = /*byte*/ n;
867                 } else {
868                     return Double.NaN;
869                 }
870                 prevc = 0;
871             } else if (c == '/' || c == ':' || c == '+' || c == '-') {
872                 prevc = c;
873             } else {
874                 int st = i - 1;
875                 int k;
876                 while (i < limit) {
877                     c = s.charAt(i);
878                     if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
879                         break;
880                     i++;
881                 }
882                 if (i <= st + 1)
883                     return Double.NaN;
884                 for (k = wtb.length; --k >= 0;)
885                     if (date_regionMatches(wtb[k], 0, s, st, i-st)) {
886                         int action = ttb[k];
887                         if (action != 0) {
888                             if (action < 0) {
889                                 /*
890                                  * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
891                                  * 12:30, instead of blindly adding 12 if PM.
892                                  */
893                                 if (hour > 12 || hour < 0) {
894                                     return Double.NaN;
895                                 } else {
896                                     if (action == -1 && hour == 12) { // am
897                                         hour = 0;
898                                     } else if (action == -2 && hour != 12) {// pm
899                                         hour += 12;
900                                     }
901                                 }
902                             } else if (action <= 13) { /* month! */
903                                 if (mon < 0) {
904                                     mon = /*byte*/ (action - 2);
905                                 } else {
906                                     return Double.NaN;
907                                 }
908                             } else {
909                                 tzoffset = action - 10000;
910                             }
911                         }
912                         break;
913                     }
914                 if (k < 0)
915                     return Double.NaN;
916                 prevc = 0;
917             }
918         }
919         if (year < 0 || mon < 0 || mday < 0)
920             return Double.NaN;
921         if (sec < 0)
922             sec = 0;
923         if (min < 0)
924             min = 0;
925         if (hour < 0)
926             hour = 0;
927         if (tzoffset == -1) { /* no time zone specified, have to use local */
928             double time;
929             time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
930             return internalUTC(time);
931         }
932
933         msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
934         msec += tzoffset * msPerMinute;
935         return msec;
936     }
937
938     private static double jsStaticFunction_parse(String s) {
939         return date_parseString(s);
940     }
941
942     private static final int FORMATSPEC_FULL = 0;
943     private static final int FORMATSPEC_DATE = 1;
944     private static final int FORMATSPEC_TIME = 2;
945
946     private static String date_format(double t, int format) {
947         if (t != t)
948             return jsFunction_NaN_date_str;
949
950         StringBuffer result = new StringBuffer(60);
951         double local = LocalTime(t);
952
953         /* offset from GMT in minutes.  The offset includes daylight savings,
954            if it applies. */
955         int minutes = (int) java.lang.Math.floor((LocalTZA + DaylightSavingTA(t))
956                                        / msPerMinute);
957         /* map 510 minutes to 0830 hours */
958         int offset = (minutes / 60) * 100 + minutes % 60;
959
960         String dateStr = Integer.toString(DateFromTime(local));
961         String hourStr = Integer.toString(HourFromTime(local));
962         String minStr = Integer.toString(MinFromTime(local));
963         String secStr = Integer.toString(SecFromTime(local));
964         String offsetStr = Integer.toString(offset > 0 ? offset : -offset);
965         int year = YearFromTime(local);
966         String yearStr = Integer.toString(year > 0 ? year : -year);
967
968         /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
969         /* Tue Oct 31 2000 */
970         /* 09:41:40 GMT-0800 (PST) */
971
972         if (format != FORMATSPEC_TIME) {
973             result.append(days[WeekDay(local)]);
974             result.append(' ');
975             result.append(months[MonthFromTime(local)]);
976             if (dateStr.length() == 1)
977                 result.append(" 0");
978             else
979                 result.append(' ');
980             result.append(dateStr);
981             result.append(' ');
982         }
983
984         if (format != FORMATSPEC_DATE) {
985             if (hourStr.length() == 1)
986                 result.append('0');
987             result.append(hourStr);
988             if (minStr.length() == 1)
989                 result.append(":0");
990             else
991                 result.append(':');
992             result.append(minStr);
993             if (secStr.length() == 1)
994                 result.append(":0");
995             else
996                 result.append(':');
997             result.append(secStr);
998             if (offset > 0)
999                 result.append(" GMT+");
1000             else
1001                 result.append(" GMT-");
1002             for (int i = offsetStr.length(); i < 4; i++)
1003                 result.append('0');
1004             result.append(offsetStr);
1005
1006             if (timeZoneFormatter == null)
1007                 timeZoneFormatter = new java.text.SimpleDateFormat("zzz");
1008
1009             if (timeZoneFormatter != null) {
1010                 result.append(" (");
1011                 java.util.Date date = new java.util.Date((long) t);
1012                 result.append(timeZoneFormatter.format(date));
1013                 result.append(')');
1014             }
1015             if (format != FORMATSPEC_TIME)
1016                 result.append(' ');
1017         }
1018
1019         if (format != FORMATSPEC_TIME) {
1020             if (year < 0)
1021                 result.append('-');
1022             for (int i = yearStr.length(); i < 4; i++)
1023                 result.append('0');
1024             result.append(yearStr);
1025         }
1026
1027         return result.toString();
1028     }
1029
1030     private static double _toNumber(Object o) { return JS.toDouble(o); }
1031     private static double _toNumber(Object[] o, int index) { return JS.toDouble(o[index]); }
1032     private static double toDouble(double d) { return d; }
1033
1034     public Date(JS.Array args_) {
1035         Object[] args = new Object[args_.length()];
1036         for(int i=0; i<args.length; i++) args[i] = args_.elementAt(i);
1037         Date obj = this;
1038
1039         // if called as a constructor with no args,
1040         // return a new Date with the current time.
1041         if (args.length == 0) {
1042             obj.date = Now();
1043             return;
1044         }
1045
1046         // if called with just one arg -
1047         if (args.length == 1) {
1048             double date;
1049             if (args[0] instanceof JS)
1050                 args[0] = ((JS) args[0]).toString();
1051             if (!(args[0] instanceof String)) {
1052                 // if it's not a string, use it as a millisecond date
1053                 date = _toNumber(args[0]);
1054             } else {
1055                 // it's a string; parse it.
1056                 String str = (String) args[0];
1057                 date = date_parseString(str);
1058             }
1059             obj.date = TimeClip(date);
1060             return;
1061         }
1062
1063         // multiple arguments; year, month, day etc.
1064         double array[] = new double[MAXARGS];
1065         int loop;
1066         double d;
1067
1068         for (loop = 0; loop < MAXARGS; loop++) {
1069             if (loop < args.length) {
1070                 d = _toNumber(args[loop]);
1071
1072                 if (d != d || Double.isInfinite(d)) {
1073                     obj.date = Double.NaN;
1074                     return;
1075                 }
1076                 array[loop] = toDouble(args[loop]);
1077             } else {
1078                 array[loop] = 0;
1079             }
1080         }
1081
1082         /* adjust 2-digit years into the 20th century */
1083         if (array[0] >= 0 && array[0] <= 99)
1084             array[0] += 1900;
1085
1086         /* if we got a 0 for 'date' (which is out of range)
1087          * pretend it's a 1 */
1088         if (array[2] < 1)
1089             array[2] = 1;
1090
1091         double day = MakeDay(array[0], array[1], array[2]);
1092         double time = MakeTime(array[3], array[4], array[5], array[6]);
1093         time = MakeDate(day, time);
1094         time = internalUTC(time);
1095         obj.date = TimeClip(time);
1096
1097         return;
1098     }
1099
1100     /* constants for toString, toUTCString */
1101     private static String jsFunction_NaN_date_str = "Invalid Date";
1102
1103     private static String[] days = {
1104         "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
1105     };
1106
1107     private static String[] months = {
1108         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1109         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1110     };
1111
1112     private static String toLocale_helper(double t,
1113                                           java.text.DateFormat formatter)
1114     {
1115         if (t != t)
1116             return jsFunction_NaN_date_str;
1117
1118         java.util.Date tempdate = new java.util.Date((long) t);
1119         return formatter.format(tempdate);
1120     }
1121
1122     private static String jsFunction_toLocaleString(double date) {
1123         if (localeDateTimeFormatter == null)
1124             localeDateTimeFormatter =
1125                 DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
1126
1127         return toLocale_helper(date, localeDateTimeFormatter);
1128     }
1129
1130     private static String jsFunction_toLocaleTimeString(double date) {
1131         if (localeTimeFormatter == null)
1132             localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG);
1133
1134         return toLocale_helper(date, localeTimeFormatter);
1135     }
1136
1137     private static String jsFunction_toLocaleDateString(double date) {
1138         if (localeDateFormatter == null)
1139             localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG);
1140
1141         return toLocale_helper(date, localeDateFormatter);
1142     }
1143
1144     private static String jsFunction_toUTCString(double date) {
1145         StringBuffer result = new StringBuffer(60);
1146
1147         String dateStr = Integer.toString(DateFromTime(date));
1148         String hourStr = Integer.toString(HourFromTime(date));
1149         String minStr = Integer.toString(MinFromTime(date));
1150         String secStr = Integer.toString(SecFromTime(date));
1151         int year = YearFromTime(date);
1152         String yearStr = Integer.toString(year > 0 ? year : -year);
1153
1154         result.append(days[WeekDay(date)]);
1155         result.append(", ");
1156         if (dateStr.length() == 1)
1157             result.append('0');
1158         result.append(dateStr);
1159         result.append(' ');
1160         result.append(months[MonthFromTime(date)]);
1161         if (year < 0)
1162             result.append(" -");
1163         else
1164             result.append(' ');
1165         int i;
1166         for (i = yearStr.length(); i < 4; i++)
1167             result.append('0');
1168         result.append(yearStr);
1169
1170         if (hourStr.length() == 1)
1171             result.append(" 0");
1172         else
1173             result.append(' ');
1174         result.append(hourStr);
1175         if (minStr.length() == 1)
1176             result.append(":0");
1177         else
1178             result.append(':');
1179         result.append(minStr);
1180         if (secStr.length() == 1)
1181             result.append(":0");
1182         else
1183             result.append(':');
1184         result.append(secStr);
1185
1186         result.append(" GMT");
1187         return result.toString();
1188     }
1189
1190     private static double jsFunction_getYear(double date) {
1191         int result = YearFromTime(LocalTime(date));
1192         result -= 1900;
1193         return result;
1194     }
1195
1196     private static double jsFunction_getTimezoneOffset(double date) {
1197         return (date - LocalTime(date)) / msPerMinute;
1198     }
1199
1200     public double jsFunction_setTime(double time) {
1201         this.date = TimeClip(time);
1202         return this.date;
1203     }
1204
1205     private double makeTime(Object[] args, int maxargs, boolean local) {
1206         int i;
1207         double conv[] = new double[4];
1208         double hour, min, sec, msec;
1209         double lorutime; /* Local or UTC version of date */
1210
1211         double time;
1212         double result;
1213
1214         double date = this.date;
1215
1216         /* just return NaN if the date is already NaN */
1217         if (date != date)
1218             return date;
1219
1220         /* Satisfy the ECMA rule that if a function is called with
1221          * fewer arguments than the specified formal arguments, the
1222          * remaining arguments are set to undefined.  Seems like all
1223          * the Date.setWhatever functions in ECMA are only varargs
1224          * beyond the first argument; this should be set to undefined
1225          * if it's not given.  This means that "d = new Date();
1226          * d.setMilliseconds()" returns NaN.  Blech.
1227          */
1228         if (args.length == 0)
1229             args = new Object[] { null };
1230
1231         for (i = 0; i < args.length && i < maxargs; i++) {
1232             conv[i] = _toNumber(args[i]);
1233
1234             // limit checks that happen in MakeTime in ECMA.
1235             if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1236                 this.date = Double.NaN;
1237                 return this.date;
1238             }
1239             conv[i] = toDouble(conv[i]);
1240         }
1241
1242         if (local)
1243             lorutime = LocalTime(date);
1244         else
1245             lorutime = date;
1246
1247         i = 0;
1248         int stop = args.length;
1249
1250         if (maxargs >= 4 && i < stop)
1251             hour = conv[i++];
1252         else
1253             hour = HourFromTime(lorutime);
1254
1255         if (maxargs >= 3 && i < stop)
1256             min = conv[i++];
1257         else
1258             min = MinFromTime(lorutime);
1259
1260         if (maxargs >= 2 && i < stop)
1261             sec = conv[i++];
1262         else
1263             sec = SecFromTime(lorutime);
1264
1265         if (maxargs >= 1 && i < stop)
1266             msec = conv[i++];
1267         else
1268             msec = msFromTime(lorutime);
1269
1270         time = MakeTime(hour, min, sec, msec);
1271         result = MakeDate(Day(lorutime), time);
1272
1273         if (local)
1274             result = internalUTC(result);
1275         date = TimeClip(result);
1276
1277         this.date = date;
1278         return date;
1279     }
1280
1281     private double jsFunction_setHours(Object[] args) {
1282         return makeTime(args, 4, true);
1283     }
1284
1285     private double jsFunction_setUTCHours(Object[] args) {
1286         return makeTime(args, 4, false);
1287     }
1288
1289     private double makeDate(Object[] args, int maxargs, boolean local) {
1290         int i;
1291         double conv[] = new double[3];
1292         double year, month, day;
1293         double lorutime; /* local or UTC version of date */
1294         double result;
1295
1296         double date = this.date;
1297
1298         /* See arg padding comment in makeTime.*/
1299         if (args.length == 0)
1300             args = new Object[] { null };
1301
1302         for (i = 0; i < args.length && i < maxargs; i++) {
1303             conv[i] = _toNumber(args[i]);
1304
1305             // limit checks that happen in MakeDate in ECMA.
1306             if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1307                 this.date = Double.NaN;
1308                 return this.date;
1309             }
1310             conv[i] = toDouble(conv[i]);
1311         }
1312
1313         /* return NaN if date is NaN and we're not setting the year,
1314          * If we are, use 0 as the time. */
1315         if (date != date) {
1316             if (args.length < 3) {
1317                 return Double.NaN;
1318             } else {
1319                 lorutime = 0;
1320             }
1321         } else {
1322             if (local)
1323                 lorutime = LocalTime(date);
1324             else
1325                 lorutime = date;
1326         }
1327
1328         i = 0;
1329         int stop = args.length;
1330
1331         if (maxargs >= 3 && i < stop)
1332             year = conv[i++];
1333         else
1334             year = YearFromTime(lorutime);
1335
1336         if (maxargs >= 2 && i < stop)
1337             month = conv[i++];
1338         else
1339             month = MonthFromTime(lorutime);
1340
1341         if (maxargs >= 1 && i < stop)
1342             day = conv[i++];
1343         else
1344             day = DateFromTime(lorutime);
1345
1346         day = MakeDay(year, month, day); /* day within year */
1347         result = MakeDate(day, TimeWithinDay(lorutime));
1348
1349         if (local)
1350             result = internalUTC(result);
1351
1352         date = TimeClip(result);
1353
1354         this.date = date;
1355         return date;
1356     }
1357
1358     private double jsFunction_setYear(double year) {
1359         double day, result;
1360         if (year != year || Double.isInfinite(year)) {
1361             this.date = Double.NaN;
1362             return this.date;
1363         }
1364
1365         if (this.date != this.date) {
1366             this.date = 0;
1367         } else {
1368             this.date = LocalTime(this.date);
1369         }
1370
1371         if (year >= 0 && year <= 99)
1372             year += 1900;
1373
1374         day = MakeDay(year, MonthFromTime(this.date), DateFromTime(this.date));
1375         result = MakeDate(day, TimeWithinDay(this.date));
1376         result = internalUTC(result);
1377
1378         this.date = TimeClip(result);
1379         return this.date;
1380     }
1381
1382     protected String getIdName(int id) {
1383             switch (id) {
1384                 case ConstructorId_UTC:     return "UTC";
1385                 case ConstructorId_parse:   return "parse";
1386                 case Id_constructor:        return "constructor"; 
1387                 case Id_toString:           return "toString";
1388                 case Id_toTimeString:       return "toTimeString";
1389                 case Id_toDateString:       return "toDateString";
1390                 case Id_toLocaleString:     return "toLocaleString";
1391                 case Id_toLocaleTimeString: return "toLocaleTimeString";
1392                 case Id_toLocaleDateString: return "toLocaleDateString";
1393                 case Id_toUTCString:        return "toUTCString";
1394                 case Id_valueOf:            return "valueOf";
1395                 case Id_getTime:            return "getTime";
1396                 case Id_getYear:            return "getYear";
1397                 case Id_getFullYear:        return "getFullYear";
1398                 case Id_getUTCFullYear:     return "getUTCFullYear";
1399                 case Id_getMonth:           return "getMonth";
1400                 case Id_getUTCMonth:        return "getUTCMonth";
1401                 case Id_getDate:            return "getDate";
1402                 case Id_getUTCDate:         return "getUTCDate";
1403                 case Id_getDay:             return "getDay";
1404                 case Id_getUTCDay:          return "getUTCDay";
1405                 case Id_getHours:           return "getHours";
1406                 case Id_getUTCHours:        return "getUTCHours";
1407                 case Id_getMinutes:         return "getMinutes";
1408                 case Id_getUTCMinutes:      return "getUTCMinutes";
1409                 case Id_getSeconds:         return "getSeconds";
1410                 case Id_getUTCSeconds:      return "getUTCSeconds";
1411                 case Id_getMilliseconds:    return "getMilliseconds";
1412                 case Id_getUTCMilliseconds: return "getUTCMilliseconds";
1413                 case Id_getTimezoneOffset:  return "getTimezoneOffset";
1414                 case Id_setTime:            return "setTime";
1415                 case Id_setMilliseconds:    return "setMilliseconds";
1416                 case Id_setUTCMilliseconds: return "setUTCMilliseconds";
1417                 case Id_setSeconds:         return "setSeconds";
1418                 case Id_setUTCSeconds:      return "setUTCSeconds";
1419                 case Id_setMinutes:         return "setMinutes";
1420                 case Id_setUTCMinutes:      return "setUTCMinutes";
1421                 case Id_setHours:           return "setHours";
1422                 case Id_setUTCHours:        return "setUTCHours";
1423                 case Id_setDate:            return "setDate";
1424                 case Id_setUTCDate:         return "setUTCDate";
1425                 case Id_setMonth:           return "setMonth";
1426                 case Id_setUTCMonth:        return "setUTCMonth";
1427                 case Id_setFullYear:        return "setFullYear";
1428                 case Id_setUTCFullYear:     return "setUTCFullYear";
1429                 case Id_setYear:            return "setYear";
1430             }
1431         return null;        
1432     }
1433
1434 // #string_id_map#
1435
1436     protected int mapNameToId(String s) {
1437         int id;
1438 // #generated# Last update: 2001-04-22 23:46:59 CEST
1439         L0: { id = 0; String X = null; int c;
1440             L: switch (s.length()) {
1441             case 6: X="getDay";id=Id_getDay; break L;
1442             case 7: switch (s.charAt(3)) {
1443                 case 'D': c=s.charAt(0);
1444                     if (c=='g') { X="getDate";id=Id_getDate; }
1445                     else if (c=='s') { X="setDate";id=Id_setDate; }
1446                     break L;
1447                 case 'T': c=s.charAt(0);
1448                     if (c=='g') { X="getTime";id=Id_getTime; }
1449                     else if (c=='s') { X="setTime";id=Id_setTime; }
1450                     break L;
1451                 case 'Y': c=s.charAt(0);
1452                     if (c=='g') { X="getYear";id=Id_getYear; }
1453                     else if (c=='s') { X="setYear";id=Id_setYear; }
1454                     break L;
1455                 case 'u': X="valueOf";id=Id_valueOf; break L;
1456                 } break L;
1457             case 8: c=s.charAt(0);
1458                 if (c=='g') {
1459                     c=s.charAt(7);
1460                     if (c=='h') { X="getMonth";id=Id_getMonth; }
1461                     else if (c=='s') { X="getHours";id=Id_getHours; }
1462                 }
1463                 else if (c=='s') {
1464                     c=s.charAt(7);
1465                     if (c=='h') { X="setMonth";id=Id_setMonth; }
1466                     else if (c=='s') { X="setHours";id=Id_setHours; }
1467                 }
1468                 else if (c=='t') { X="toString";id=Id_toString; }
1469                 break L;
1470             case 9: X="getUTCDay";id=Id_getUTCDay; break L;
1471             case 10: c=s.charAt(3);
1472                 if (c=='M') {
1473                     c=s.charAt(0);
1474                     if (c=='g') { X="getMinutes";id=Id_getMinutes; }
1475                     else if (c=='s') { X="setMinutes";id=Id_setMinutes; }
1476                 }
1477                 else if (c=='S') {
1478                     c=s.charAt(0);
1479                     if (c=='g') { X="getSeconds";id=Id_getSeconds; }
1480                     else if (c=='s') { X="setSeconds";id=Id_setSeconds; }
1481                 }
1482                 else if (c=='U') {
1483                     c=s.charAt(0);
1484                     if (c=='g') { X="getUTCDate";id=Id_getUTCDate; }
1485                     else if (c=='s') { X="setUTCDate";id=Id_setUTCDate; }
1486                 }
1487                 break L;
1488             case 11: switch (s.charAt(3)) {
1489                 case 'F': c=s.charAt(0);
1490                     if (c=='g') { X="getFullYear";id=Id_getFullYear; }
1491                     else if (c=='s') { X="setFullYear";id=Id_setFullYear; }
1492                     break L;
1493                 case 'M': X="toGMTString";id=Id_toGMTString; break L;
1494                 case 'T': X="toUTCString";id=Id_toUTCString; break L;
1495                 case 'U': c=s.charAt(0);
1496                     if (c=='g') {
1497                         c=s.charAt(9);
1498                         if (c=='r') { X="getUTCHours";id=Id_getUTCHours; }
1499                         else if (c=='t') { X="getUTCMonth";id=Id_getUTCMonth; }
1500                     }
1501                     else if (c=='s') {
1502                         c=s.charAt(9);
1503                         if (c=='r') { X="setUTCHours";id=Id_setUTCHours; }
1504                         else if (c=='t') { X="setUTCMonth";id=Id_setUTCMonth; }
1505                     }
1506                     break L;
1507                 case 's': X="constructor";id=Id_constructor; break L;
1508                 } break L;
1509             case 12: c=s.charAt(2);
1510                 if (c=='D') { X="toDateString";id=Id_toDateString; }
1511                 else if (c=='T') { X="toTimeString";id=Id_toTimeString; }
1512                 break L;
1513             case 13: c=s.charAt(0);
1514                 if (c=='g') {
1515                     c=s.charAt(6);
1516                     if (c=='M') { X="getUTCMinutes";id=Id_getUTCMinutes; }
1517                     else if (c=='S') { X="getUTCSeconds";id=Id_getUTCSeconds; }
1518                 }
1519                 else if (c=='s') {
1520                     c=s.charAt(6);
1521                     if (c=='M') { X="setUTCMinutes";id=Id_setUTCMinutes; }
1522                     else if (c=='S') { X="setUTCSeconds";id=Id_setUTCSeconds; }
1523                 }
1524                 break L;
1525             case 14: c=s.charAt(0);
1526                 if (c=='g') { X="getUTCFullYear";id=Id_getUTCFullYear; }
1527                 else if (c=='s') { X="setUTCFullYear";id=Id_setUTCFullYear; }
1528                 else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; }
1529                 break L;
1530             case 15: c=s.charAt(0);
1531                 if (c=='g') { X="getMilliseconds";id=Id_getMilliseconds; }
1532                 else if (c=='s') { X="setMilliseconds";id=Id_setMilliseconds; }
1533                 break L;
1534             case 17: X="getTimezoneOffset";id=Id_getTimezoneOffset; break L;
1535             case 18: c=s.charAt(0);
1536                 if (c=='g') { X="getUTCMilliseconds";id=Id_getUTCMilliseconds; }
1537                 else if (c=='s') { X="setUTCMilliseconds";id=Id_setUTCMilliseconds; }
1538                 else if (c=='t') {
1539                     c=s.charAt(8);
1540                     if (c=='D') { X="toLocaleDateString";id=Id_toLocaleDateString; }
1541                     else if (c=='T') { X="toLocaleTimeString";id=Id_toLocaleTimeString; }
1542                 }
1543                 break L;
1544             }
1545             if (X!=null && X!=s && !X.equals(s)) id = 0;
1546         }
1547 // #/generated#
1548         return id;
1549     }
1550
1551     private static final int
1552         ConstructorId_UTC       = -2,
1553         ConstructorId_parse     = -1,
1554
1555         Id_constructor          =  1,
1556         Id_toString             =  2,
1557         Id_toTimeString         =  3,
1558         Id_toDateString         =  4,
1559         Id_toLocaleString       =  5,
1560         Id_toLocaleTimeString   =  6,
1561         Id_toLocaleDateString   =  7,
1562         Id_toUTCString          =  8,
1563         Id_valueOf              =  9,
1564         Id_getTime              = 10,
1565         Id_getYear              = 11,
1566         Id_getFullYear          = 12,
1567         Id_getUTCFullYear       = 13,
1568         Id_getMonth             = 14,
1569         Id_getUTCMonth          = 15,
1570         Id_getDate              = 16,
1571         Id_getUTCDate           = 17,
1572         Id_getDay               = 18,
1573         Id_getUTCDay            = 19,
1574         Id_getHours             = 20,
1575         Id_getUTCHours          = 21,
1576         Id_getMinutes           = 22,
1577         Id_getUTCMinutes        = 23,
1578         Id_getSeconds           = 24,
1579         Id_getUTCSeconds        = 25,
1580         Id_getMilliseconds      = 26,
1581         Id_getUTCMilliseconds   = 27,
1582         Id_getTimezoneOffset    = 28,
1583         Id_setTime              = 29,
1584         Id_setMilliseconds      = 30,
1585         Id_setUTCMilliseconds   = 31,
1586         Id_setSeconds           = 32,
1587         Id_setUTCSeconds        = 33,
1588         Id_setMinutes           = 34,
1589         Id_setUTCMinutes        = 35,
1590         Id_setHours             = 36,
1591         Id_setUTCHours          = 37,
1592         Id_setDate              = 38,
1593         Id_setUTCDate           = 39,
1594         Id_setMonth             = 40,
1595         Id_setUTCMonth          = 41,
1596         Id_setFullYear          = 42,
1597         Id_setUTCFullYear       = 43,
1598         Id_setYear              = 44,
1599
1600         MAX_PROTOTYPE_ID        = 44;
1601
1602     private static final int
1603         Id_toGMTString  =  Id_toUTCString; // Alias, see Ecma B.2.6
1604 // #/string_id_map#
1605
1606     /* cached values */
1607     private static java.util.TimeZone thisTimeZone;
1608     private static double LocalTZA;
1609     private static java.text.DateFormat timeZoneFormatter;
1610     private static java.text.DateFormat localeDateTimeFormatter;
1611     private static java.text.DateFormat localeDateFormatter;
1612     private static java.text.DateFormat localeTimeFormatter;
1613
1614     private double date;
1615
1616     public long getRawTime() { return (long)this.date; }
1617 }
1618
1619