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