~ubuntu-branches/ubuntu/karmic/rhino/karmic

« back to all changes in this revision

Viewing changes to src/org/mozilla/javascript/NativeDate.java

  • Committer: Bazaar Package Importer
  • Author(s): Jerry Haltom
  • Date: 2005-03-19 16:56:07 UTC
  • mto: (11.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050319165607-geu3j3fnqlkpqkh1
Tags: upstream-1.6.R1
ImportĀ upstreamĀ versionĀ 1.6.R1

Show diffs side-by-side

added added

removed removed

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