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