1
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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/
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.
13
* The Original Code is Rhino code, released
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
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.
37
package org.mozilla.javascript;
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;
47
* This class implements the Date native object.
51
public class NativeDate extends IdScriptable {
53
public static void init(Context cx, Scriptable scope, boolean sealed) {
54
NativeDate obj = new NativeDate();
55
obj.prototypeFlag = true;
57
// Set the value of the prototype Date to NaN ('invalid date');
58
obj.date = ScriptRuntime.NaN;
60
obj.addAsPrototype(MAX_PROTOTYPE_ID, cx, scope, sealed);
64
if (thisTimeZone == null) {
65
// j.u.TimeZone is synchronized, so setting class statics from it
67
thisTimeZone = java.util.TimeZone.getDefault();
68
LocalTZA = thisTimeZone.getRawOffset();
72
public String getClassName() {
76
public Object getDefaultValue(Class typeHint) {
78
typeHint = ScriptRuntime.StringClass;
79
return super.getDefaultValue(typeHint);
82
protected void fillConstructorProperties
83
(Context cx, IdFunction ctor, boolean sealed)
85
addIdFunctionProperty(ctor, ConstructorId_UTC, sealed);
86
addIdFunctionProperty(ctor, ConstructorId_parse, sealed);
87
super.fillConstructorProperties(cx, ctor, sealed);
90
public int methodArity(int 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;
141
return super.methodArity(methodId);
144
public Object execMethod
145
(int methodId, IdFunction f,
146
Context cx, Scriptable scope, Scriptable thisObj, Object[] args)
147
throws JavaScriptException
151
case ConstructorId_UTC:
152
return wrap_double(jsStaticFunction_UTC(args));
154
case ConstructorId_parse:
155
return wrap_double(jsStaticFunction_parse
156
(ScriptRuntime.toString(args, 0)));
159
return jsConstructor(args, thisObj == null);
162
double t = realThis(thisObj, f, true).date;
163
return date_format(t, FORMATSPEC_FULL);
166
case Id_toTimeString: {
167
double t = realThis(thisObj, f, true).date;
168
return date_format(t, FORMATSPEC_TIME);
171
case Id_toDateString: {
172
double t = realThis(thisObj, f, true).date;
173
return date_format(t, FORMATSPEC_DATE);
176
case Id_toLocaleString: {
177
double t = realThis(thisObj, f, true).date;
178
return jsFunction_toLocaleString(t);
181
case Id_toLocaleTimeString: {
182
double t = realThis(thisObj, f, true).date;
183
return jsFunction_toLocaleTimeString(t);
186
case Id_toLocaleDateString: {
187
double t = realThis(thisObj, f, true).date;
188
return jsFunction_toLocaleDateString(t);
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;
198
return wrap_double(realThis(thisObj, f, true).date);
201
return wrap_double(realThis(thisObj, f, true).date);
204
double t = realThis(thisObj, f, true).date;
205
if (t == t) { t = jsFunction_getYear(cx, t); }
206
return wrap_double(t);
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);
215
case Id_getUTCFullYear: {
216
double t = realThis(thisObj, f, true).date;
217
if (t == t) { t = YearFromTime(t); }
218
return wrap_double(t);
222
double t = realThis(thisObj, f, true).date;
223
if (t == t) { t = MonthFromTime(LocalTime(t)); }
224
return wrap_double(t);
227
case Id_getUTCMonth: {
228
double t = realThis(thisObj, f, true).date;
229
if (t == t) { t = MonthFromTime(t); }
230
return wrap_double(t);
234
double t = realThis(thisObj, f, true).date;
235
if (t == t) { t = DateFromTime(LocalTime(t)); }
236
return wrap_double(t);
239
case Id_getUTCDate: {
240
double t = realThis(thisObj, f, true).date;
241
if (t == t) { t = DateFromTime(t); }
242
return wrap_double(t);
246
double t = realThis(thisObj, f, true).date;
247
if (t == t) { t = WeekDay(LocalTime(t)); }
248
return wrap_double(t);
252
double t = realThis(thisObj, f, true).date;
253
if (t == t) { t = WeekDay(t); }
254
return wrap_double(t);
258
double t = realThis(thisObj, f, true).date;
259
if (t == t) { t = HourFromTime(LocalTime(t)); }
260
return wrap_double(t);
263
case Id_getUTCHours: {
264
double t = realThis(thisObj, f, true).date;
265
if (t == t) { t = HourFromTime(t); }
266
return wrap_double(t);
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);
275
case Id_getUTCMinutes: {
276
double t = realThis(thisObj, f, true).date;
277
if (t == t) { t = MinFromTime(t); }
278
return wrap_double(t);
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);
287
case Id_getUTCSeconds: {
288
double t = realThis(thisObj, f, true).date;
289
if (t == t) { t = SecFromTime(t); }
290
return wrap_double(t);
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);
299
case Id_getUTCMilliseconds: {
300
double t = realThis(thisObj, f, true).date;
301
if (t == t) { t = msFromTime(t); }
302
return wrap_double(t);
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);
312
return wrap_double(realThis(thisObj, f, true).
313
jsFunction_setTime(ScriptRuntime.toNumber(args, 0)));
315
case Id_setMilliseconds:
316
return wrap_double(realThis(thisObj, f, false).
317
makeTime(args, 1, true));
319
case Id_setUTCMilliseconds:
320
return wrap_double(realThis(thisObj, f, false).
321
makeTime(args, 1, false));
324
return wrap_double(realThis(thisObj, f, false).
325
makeTime(args, 2, true));
327
case Id_setUTCSeconds:
328
return wrap_double(realThis(thisObj, f, false).
329
makeTime(args, 2, false));
332
return wrap_double(realThis(thisObj, f, false).
333
makeTime(args, 3, true));
335
case Id_setUTCMinutes:
336
return wrap_double(realThis(thisObj, f, false).
337
makeTime(args, 3, false));
340
return wrap_double(realThis(thisObj, f, false).
341
makeTime(args, 4, true));
344
return wrap_double(realThis(thisObj, f, false).
345
makeTime(args, 4, false));
348
return wrap_double(realThis(thisObj, f, false).
349
makeDate(args, 1, true));
352
return wrap_double(realThis(thisObj, f, false).
353
makeDate(args, 1, false));
356
return wrap_double(realThis(thisObj, f, false).
357
makeDate(args, 2, true));
360
return wrap_double(realThis(thisObj, f, false).
361
makeDate(args, 2, false));
364
return wrap_double(realThis(thisObj, f, false).
365
makeDate(args, 3, true));
367
case Id_setUTCFullYear:
368
return wrap_double(realThis(thisObj, f, false).
369
makeDate(args, 3, false));
372
return wrap_double(realThis(thisObj, f, false).
373
jsFunction_setYear(ScriptRuntime.toNumber(args, 0)));
377
return super.execMethod(methodId, f, cx, scope, thisObj, args);
380
private NativeDate realThis(Scriptable thisObj, IdFunction f,
383
while (!(thisObj instanceof NativeDate)) {
384
thisObj = nextInstanceCheck(thisObj, f, readOnly);
386
return (NativeDate)thisObj;
389
/* ECMA helper functions */
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);
403
private static double Day(double t) {
404
return Math.floor(t / msPerDay);
407
private static double TimeWithinDay(double t) {
409
result = t % msPerDay;
415
private static int DaysInYear(int y) {
416
if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
423
/* math here has to be f.p, because we need
424
* floor((1968 - 1969) / 4) == -1
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)));
431
private static double TimeFromYear(double y) {
432
return DayFromYear(y) * msPerDay;
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;
440
/* above doesn't work for negative dates... */
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
455
if (TimeFromYear(mid) > t) {
458
if (TimeFromYear(mid) <= t) {
460
if (TimeFromYear(temp) > t) {
470
private static boolean InLeapYear(double t) {
471
return DaysInYear(YearFromTime(t)) == 366;
474
private static int DayWithinYear(double t) {
475
int year = YearFromTime(t);
476
return (int) (Day(t) - DayFromYear(year));
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.
483
private static double DayFromMonth(int m, boolean leap) {
486
if (m >= 7) { day += m / 2 - 1; }
487
else if (m >= 2) { day += (m - 1) / 2 - 1; }
490
if (leap && m >= 2) { ++day; }
495
private static int MonthFromTime(double t) {
498
d = DayWithinYear(t);
503
// Originally coded as step += (InLeapYear(t) ? 29 : 28);
504
// but some jits always returned 28!
512
if (d < (step += 31))
514
if (d < (step += 30))
516
if (d < (step += 31))
518
if (d < (step += 30))
520
if (d < (step += 31))
522
if (d < (step += 31))
524
if (d < (step += 30))
526
if (d < (step += 31))
528
if (d < (step += 30))
533
private static int DateFromTime(double t) {
536
d = DayWithinYear(t);
537
if (d <= (next = 30))
541
// Originally coded as next += (InLeapYear(t) ? 29 : 28);
542
// but some jits always returned 28!
551
if (d <= (next += 31))
554
if (d <= (next += 30))
557
if (d <= (next += 31))
560
if (d <= (next += 30))
563
if (d <= (next += 31))
566
if (d <= (next += 31))
569
if (d <= (next += 30))
572
if (d <= (next += 31))
575
if (d <= (next += 30))
582
private static int WeekDay(double t) {
591
private static double Now() {
592
return (double) System.currentTimeMillis();
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.
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))
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.
618
// Hardcode the assumption that the changeover always
619
// happens at 2:00 AM:
620
t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);
622
int year = YearFromTime(t);
623
double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0,
628
(int)TimeWithinDay(t));
630
if ((offset - LocalTZA) != 0)
634
// return offset - LocalTZA;
638
private static double LocalTime(double t) {
639
return t + LocalTZA + DaylightSavingTA(t);
642
private static double internalUTC(double t) {
643
return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
646
private static int HourFromTime(double t) {
648
result = Math.floor(t / msPerHour) % HoursPerDay;
650
result += HoursPerDay;
654
private static int MinFromTime(double t) {
656
result = Math.floor(t / msPerMinute) % MinutesPerHour;
658
result += MinutesPerHour;
662
private static int SecFromTime(double t) {
664
result = Math.floor(t / msPerSecond) % SecondsPerMinute;
666
result += SecondsPerMinute;
670
private static int msFromTime(double t) {
672
result = t % msPerSecond;
674
result += msPerSecond;
678
private static double MakeTime(double hour, double min,
679
double sec, double ms)
681
return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)
685
private static double MakeDay(double year, double month, double date) {
691
year += Math.floor(month / 12);
697
leap = (DaysInYear((int) year) == 366);
699
yearday = Math.floor(TimeFromYear(year) / msPerDay);
700
monthday = DayFromMonth((int) month, leap);
708
private static double MakeDate(double day, double time) {
709
return day * msPerDay + time;
712
private static double TimeClip(double d) {
714
d == Double.POSITIVE_INFINITY ||
715
d == Double.NEGATIVE_INFINITY ||
716
Math.abs(d) > HalfTimeDomain)
718
return ScriptRuntime.NaN;
721
return Math.floor(d + 0.);
723
return Math.ceil(d + 0.);
726
/* end of ECMA helper functions */
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,
738
day = MakeDay(year, mon, mday);
739
time = MakeTime(hour, min, sec, msec);
740
result = MakeDate(day, time);
745
private static final int MAXARGS = 7;
746
private static double jsStaticFunction_UTC(Object[] args) {
747
double array[] = new double[MAXARGS];
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;
757
array[loop] = ScriptRuntime.toInteger(args[loop]);
763
/* adjust 2-digit years into the 20th century */
764
if (array[0] >= 0 && array[0] <= 99)
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) */
772
d = date_msecFromDate(array[0], array[1], array[2],
773
array[3], array[4], array[5], array[6]);
776
// return new Double(d);
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?
785
/* for use by date_parse */
787
/* replace this with byte arrays? Cheaper? */
788
private static String wtb[] = {
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 */
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
809
/* helper for date_parse */
810
private static boolean date_regionMatches(String s1, int s1off,
811
String s2, int s2off,
814
boolean result = false;
815
/* return true if matches, otherwise, false */
816
int s1len = s1.length();
817
int s2len = s2.length();
819
while (count > 0 && s1off < s1len && s2off < s2len) {
820
if (Character.toLowerCase(s1.charAt(s1off)) !=
821
Character.toLowerCase(s2.charAt(s2off)))
834
private static double date_parseString(String s) {
847
double tzoffset = -1;
850
boolean seenplusminus = false;
852
if (s == null) // ??? Will s be null?
853
return ScriptRuntime.NaN;
858
if (c <= ' ' || c == ',' || c == '-') {
861
if (c == '-' && '0' <= si && si <= '9') {
867
if (c == '(') { /* comments) */
880
if ('0' <= c && c <= '9') {
882
while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
883
n = n * 10 + c - '0';
887
/* allow TZA before the year, so
888
* 'Wed Nov 05 21:49:11 GMT-0800 1997'
891
/* uses of seenplusminus allow : in TZA, so Java
892
* no-timezone style of GMT+4:30 works
894
if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
895
/* make ':' case below change tzoffset */
896
seenplusminus = true;
900
n = n * 60; /* EG. "GMT-3" */
902
n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
903
if (prevc == '+') /* plus means east of GMT */
905
if (tzoffset != 0 && tzoffset != -1)
906
return ScriptRuntime.NaN;
908
} else if (n >= 70 ||
909
(prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
911
return ScriptRuntime.NaN;
912
else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
913
year = n < 100 ? n + 1900 : n;
915
return ScriptRuntime.NaN;
916
} else if (c == ':') {
922
return ScriptRuntime.NaN;
923
} else if (c == '/') {
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 */
937
} else if (hour >= 0 && min < 0) {
939
} else if (min >= 0 && sec < 0) {
941
} else if (mday < 0) {
944
return ScriptRuntime.NaN;
947
} else if (c == '/' || c == ':' || c == '+' || c == '-') {
954
if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
959
return ScriptRuntime.NaN;
960
for (k = wtb.length; --k >= 0;)
961
if (date_regionMatches(wtb[k], 0, s, st, i-st)) {
966
* AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
967
* 12:30, instead of blindly adding 12 if PM.
969
if (hour > 12 || hour < 0) {
970
return ScriptRuntime.NaN;
972
if (action == -1 && hour == 12) { // am
974
} else if (action == -2 && hour != 12) {// pm
978
} else if (action <= 13) { /* month! */
980
mon = /*byte*/ (action - 2);
982
return ScriptRuntime.NaN;
985
tzoffset = action - 10000;
991
return ScriptRuntime.NaN;
995
if (year < 0 || mon < 0 || mday < 0)
996
return ScriptRuntime.NaN;
1003
if (tzoffset == -1) { /* no time zone specified, have to use local */
1005
time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
1006
return internalUTC(time);
1009
msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
1010
msec += tzoffset * msPerMinute;
1014
private static double jsStaticFunction_parse(String s) {
1015
return date_parseString(s);
1018
private static final int FORMATSPEC_FULL = 0;
1019
private static final int FORMATSPEC_DATE = 1;
1020
private static final int FORMATSPEC_TIME = 2;
1022
private static String date_format(double t, int format) {
1024
return jsFunction_NaN_date_str;
1026
StringBuffer result = new StringBuffer(60);
1027
double local = LocalTime(t);
1029
/* offset from GMT in minutes. The offset includes daylight savings,
1031
int minutes = (int) Math.floor((LocalTZA + DaylightSavingTA(t))
1033
/* map 510 minutes to 0830 hours */
1034
int offset = (minutes / 60) * 100 + minutes % 60;
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);
1044
/* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
1045
/* Tue Oct 31 2000 */
1046
/* 09:41:40 GMT-0800 (PST) */
1048
if (format != FORMATSPEC_TIME) {
1049
result.append(days[WeekDay(local)]);
1051
result.append(months[MonthFromTime(local)]);
1052
if (dateStr.length() == 1)
1053
result.append(" 0");
1056
result.append(dateStr);
1060
if (format != FORMATSPEC_DATE) {
1061
if (hourStr.length() == 1)
1063
result.append(hourStr);
1064
if (minStr.length() == 1)
1065
result.append(":0");
1068
result.append(minStr);
1069
if (secStr.length() == 1)
1070
result.append(":0");
1073
result.append(secStr);
1075
result.append(" GMT+");
1077
result.append(" GMT-");
1078
for (int i = offsetStr.length(); i < 4; i++)
1080
result.append(offsetStr);
1082
if (timeZoneFormatter == null)
1083
timeZoneFormatter = new java.text.SimpleDateFormat("zzz");
1085
if (timeZoneFormatter != null) {
1086
result.append(" (");
1087
java.util.Date date = new Date((long) t);
1088
result.append(timeZoneFormatter.format(date));
1091
if (format != FORMATSPEC_TIME)
1095
if (format != FORMATSPEC_TIME) {
1098
for (int i = yearStr.length(); i < 4; i++)
1100
result.append(yearStr);
1103
return result.toString();
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.
1111
return date_format(Now(), FORMATSPEC_FULL);
1113
NativeDate obj = new NativeDate();
1115
// if called as a constructor with no args,
1116
// return a new Date with the current time.
1117
if (args.length == 0) {
1122
// if called with just one arg -
1123
if (args.length == 1) {
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]);
1131
// it's a string; parse it.
1132
String str = (String) args[0];
1133
date = date_parseString(str);
1135
obj.date = TimeClip(date);
1139
// multiple arguments; year, month, day etc.
1140
double array[] = new double[MAXARGS];
1144
for (loop = 0; loop < MAXARGS; loop++) {
1145
if (loop < args.length) {
1146
d = ScriptRuntime.toNumber(args[loop]);
1148
if (d != d || Double.isInfinite(d)) {
1149
obj.date = ScriptRuntime.NaN;
1152
array[loop] = ScriptRuntime.toInteger(args[loop]);
1158
/* adjust 2-digit years into the 20th century */
1159
if (array[0] >= 0 && array[0] <= 99)
1162
/* if we got a 0 for 'date' (which is out of range)
1163
* pretend it's a 1 */
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);
1176
/* constants for toString, toUTCString */
1177
private static String jsFunction_NaN_date_str = "Invalid Date";
1179
private static String[] days = {
1180
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
1183
private static String[] months = {
1184
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1185
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1188
private static String toLocale_helper(double t,
1189
java.text.DateFormat formatter)
1192
return jsFunction_NaN_date_str;
1194
java.util.Date tempdate = new Date((long) t);
1195
return formatter.format(tempdate);
1198
private static String jsFunction_toLocaleString(double date) {
1199
if (localeDateTimeFormatter == null)
1200
localeDateTimeFormatter =
1201
DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
1203
return toLocale_helper(date, localeDateTimeFormatter);
1206
private static String jsFunction_toLocaleTimeString(double date) {
1207
if (localeTimeFormatter == null)
1208
localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG);
1210
return toLocale_helper(date, localeTimeFormatter);
1213
private static String jsFunction_toLocaleDateString(double date) {
1214
if (localeDateFormatter == null)
1215
localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG);
1217
return toLocale_helper(date, localeDateFormatter);
1220
private static String jsFunction_toUTCString(double date) {
1221
StringBuffer result = new StringBuffer(60);
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);
1230
result.append(days[WeekDay(date)]);
1231
result.append(", ");
1232
if (dateStr.length() == 1)
1234
result.append(dateStr);
1236
result.append(months[MonthFromTime(date)]);
1238
result.append(" -");
1242
for (i = yearStr.length(); i < 4; i++)
1244
result.append(yearStr);
1246
if (hourStr.length() == 1)
1247
result.append(" 0");
1250
result.append(hourStr);
1251
if (minStr.length() == 1)
1252
result.append(":0");
1255
result.append(minStr);
1256
if (secStr.length() == 1)
1257
result.append(":0");
1260
result.append(secStr);
1262
result.append(" GMT");
1263
return result.toString();
1266
private static double jsFunction_getYear(Context cx, double date) {
1268
int result = YearFromTime(LocalTime(date));
1270
if (cx.hasFeature(Context.FEATURE_NON_ECMA_GET_YEAR)) {
1271
if (result >= 1900 && result < 2000) {
1281
private static double jsFunction_getTimezoneOffset(double date) {
1282
return (date - LocalTime(date)) / msPerMinute;
1285
private double jsFunction_setTime(double time) {
1286
this.date = TimeClip(time);
1290
private double makeTime(Object[] args, int maxargs, boolean local) {
1292
double conv[] = new double[4];
1293
double hour, min, sec, msec;
1294
double lorutime; /* Local or UTC version of date */
1299
double date = this.date;
1301
/* just return NaN if the date is already NaN */
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.
1313
if (args.length == 0)
1314
args = ScriptRuntime.padArguments(args, 1);
1316
for (i = 0; i < args.length && i < maxargs; i++) {
1317
conv[i] = ScriptRuntime.toNumber(args[i]);
1319
// limit checks that happen in MakeTime in ECMA.
1320
if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1321
this.date = ScriptRuntime.NaN;
1324
conv[i] = ScriptRuntime.toInteger(conv[i]);
1328
lorutime = LocalTime(date);
1333
int stop = args.length;
1335
if (maxargs >= 4 && i < stop)
1338
hour = HourFromTime(lorutime);
1340
if (maxargs >= 3 && i < stop)
1343
min = MinFromTime(lorutime);
1345
if (maxargs >= 2 && i < stop)
1348
sec = SecFromTime(lorutime);
1350
if (maxargs >= 1 && i < stop)
1353
msec = msFromTime(lorutime);
1355
time = MakeTime(hour, min, sec, msec);
1356
result = MakeDate(Day(lorutime), time);
1359
result = internalUTC(result);
1360
date = TimeClip(result);
1366
private double jsFunction_setHours(Object[] args) {
1367
return makeTime(args, 4, true);
1370
private double jsFunction_setUTCHours(Object[] args) {
1371
return makeTime(args, 4, false);
1374
private double makeDate(Object[] args, int maxargs, boolean local) {
1376
double conv[] = new double[3];
1377
double year, month, day;
1378
double lorutime; /* local or UTC version of date */
1381
double date = this.date;
1383
/* See arg padding comment in makeTime.*/
1384
if (args.length == 0)
1385
args = ScriptRuntime.padArguments(args, 1);
1387
for (i = 0; i < args.length && i < maxargs; i++) {
1388
conv[i] = ScriptRuntime.toNumber(args[i]);
1390
// limit checks that happen in MakeDate in ECMA.
1391
if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1392
this.date = ScriptRuntime.NaN;
1395
conv[i] = ScriptRuntime.toInteger(conv[i]);
1398
/* return NaN if date is NaN and we're not setting the year,
1399
* If we are, use 0 as the time. */
1401
if (args.length < 3) {
1402
return ScriptRuntime.NaN;
1408
lorutime = LocalTime(date);
1414
int stop = args.length;
1416
if (maxargs >= 3 && i < stop)
1419
year = YearFromTime(lorutime);
1421
if (maxargs >= 2 && i < stop)
1424
month = MonthFromTime(lorutime);
1426
if (maxargs >= 1 && i < stop)
1429
day = DateFromTime(lorutime);
1431
day = MakeDay(year, month, day); /* day within year */
1432
result = MakeDate(day, TimeWithinDay(lorutime));
1435
result = internalUTC(result);
1437
date = TimeClip(result);
1443
private double jsFunction_setYear(double year) {
1445
if (year != year || Double.isInfinite(year)) {
1446
this.date = ScriptRuntime.NaN;
1450
if (this.date != this.date) {
1453
this.date = LocalTime(this.date);
1456
if (year >= 0 && year <= 99)
1459
day = MakeDay(year, MonthFromTime(this.date), DateFromTime(this.date));
1460
result = MakeDate(day, TimeWithinDay(this.date));
1461
result = internalUTC(result);
1463
this.date = TimeClip(result);
1467
protected String getIdName(int id) {
1468
if (prototypeFlag) {
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";
1523
protected int mapNameToId(String s) {
1524
if (!prototypeFlag) { return 0; }
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; }
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; }
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; }
1543
case 'u': X="valueOf";id=Id_valueOf; break L;
1545
case 8: c=s.charAt(0);
1548
if (c=='h') { X="getMonth";id=Id_getMonth; }
1549
else if (c=='s') { X="getHours";id=Id_getHours; }
1553
if (c=='h') { X="setMonth";id=Id_setMonth; }
1554
else if (c=='s') { X="setHours";id=Id_setHours; }
1556
else if (c=='t') { X="toString";id=Id_toString; }
1558
case 9: X="getUTCDay";id=Id_getUTCDay; break L;
1559
case 10: c=s.charAt(3);
1562
if (c=='g') { X="getMinutes";id=Id_getMinutes; }
1563
else if (c=='s') { X="setMinutes";id=Id_setMinutes; }
1567
if (c=='g') { X="getSeconds";id=Id_getSeconds; }
1568
else if (c=='s') { X="setSeconds";id=Id_setSeconds; }
1572
if (c=='g') { X="getUTCDate";id=Id_getUTCDate; }
1573
else if (c=='s') { X="setUTCDate";id=Id_setUTCDate; }
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; }
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);
1586
if (c=='r') { X="getUTCHours";id=Id_getUTCHours; }
1587
else if (c=='t') { X="getUTCMonth";id=Id_getUTCMonth; }
1591
if (c=='r') { X="setUTCHours";id=Id_setUTCHours; }
1592
else if (c=='t') { X="setUTCMonth";id=Id_setUTCMonth; }
1595
case 's': X="constructor";id=Id_constructor; 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; }
1601
case 13: c=s.charAt(0);
1604
if (c=='M') { X="getUTCMinutes";id=Id_getUTCMinutes; }
1605
else if (c=='S') { X="getUTCSeconds";id=Id_getUTCSeconds; }
1609
if (c=='M') { X="setUTCMinutes";id=Id_setUTCMinutes; }
1610
else if (c=='S') { X="setUTCSeconds";id=Id_setUTCSeconds; }
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; }
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; }
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; }
1628
if (c=='D') { X="toLocaleDateString";id=Id_toLocaleDateString; }
1629
else if (c=='T') { X="toLocaleTimeString";id=Id_toLocaleTimeString; }
1633
if (X!=null && X!=s && !X.equals(s)) id = 0;
1639
private static final int
1640
ConstructorId_UTC = -2,
1641
ConstructorId_parse = -1,
1645
Id_toTimeString = 3,
1646
Id_toDateString = 4,
1647
Id_toLocaleString = 5,
1648
Id_toLocaleTimeString = 6,
1649
Id_toLocaleDateString = 7,
1654
Id_getFullYear = 12,
1655
Id_getUTCFullYear = 13,
1657
Id_getUTCMonth = 15,
1663
Id_getUTCHours = 21,
1665
Id_getUTCMinutes = 23,
1667
Id_getUTCSeconds = 25,
1668
Id_getMilliseconds = 26,
1669
Id_getUTCMilliseconds = 27,
1670
Id_getTimezoneOffset = 28,
1672
Id_setMilliseconds = 30,
1673
Id_setUTCMilliseconds = 31,
1675
Id_setUTCSeconds = 33,
1677
Id_setUTCMinutes = 35,
1679
Id_setUTCHours = 37,
1683
Id_setUTCMonth = 41,
1684
Id_setFullYear = 42,
1685
Id_setUTCFullYear = 43,
1688
MAX_PROTOTYPE_ID = 44;
1690
private static final int
1691
Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6
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;
1702
private double date;
1704
private boolean prototypeFlag;
1
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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/
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.
13
* The Original Code is Rhino code, released
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
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.
37
package org.mozilla.javascript;
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;
47
* This class implements the Date native object.
51
final class NativeDate extends IdScriptableObject
53
private static final Object DATE_TAG = new Object();
55
private static final String js_NaN_date_str = "Invalid Date";
57
static void init(Context cx, Scriptable scope, boolean sealed)
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);
67
if (thisTimeZone == null) {
68
// j.u.TimeZone is synchronized, so setting class statics from it
70
thisTimeZone = java.util.TimeZone.getDefault();
71
LocalTZA = thisTimeZone.getRawOffset();
75
public String getClassName()
80
public Object getDefaultValue(Class typeHint)
83
typeHint = ScriptRuntime.StringClass;
84
return super.getDefaultValue(typeHint);
87
double getJSTimeValue()
92
protected void fillConstructorProperties(IdFunctionObject ctor)
94
addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_now,
96
addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_parse,
98
addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_UTC,
100
super.fillConstructorProperties(ctor);
103
protected void initPrototypeId(int 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));
155
initPrototypeMethod(DATE_TAG, id, s, arity);
158
public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
159
Scriptable thisObj, Object[] args)
161
if (!f.hasTag(DATE_TAG)) {
162
return super.execIdCall(f, cx, scope, thisObj, args);
164
int id = f.methodId();
166
case ConstructorId_now:
167
return ScriptRuntime.wrapNumber(now());
169
case ConstructorId_parse:
171
String dataStr = ScriptRuntime.toString(args, 0);
172
return ScriptRuntime.wrapNumber(date_parseString(dataStr));
175
case ConstructorId_UTC:
176
return ScriptRuntime.wrapNumber(jsStaticFunction_UTC(args));
180
// if called as a function, just return a string
181
// representing the current time.
183
return date_format(now(), Id_toString);
184
return jsConstructor(args);
188
// The rest of Date.prototype methods require thisObj to be Date
190
if (!(thisObj instanceof NativeDate))
191
throw incompatibleCallError(f);
192
NativeDate realThis = (NativeDate)thisObj;
193
double t = realThis.date;
198
case Id_toTimeString:
199
case Id_toDateString:
201
return date_format(t, id);
203
return js_NaN_date_str;
205
case Id_toLocaleString:
206
case Id_toLocaleTimeString:
207
case Id_toLocaleDateString:
209
return toLocale_helper(t, id);
211
return js_NaN_date_str;
215
return js_toUTCString(t);
217
return js_NaN_date_str;
220
return "(new Date("+ScriptRuntime.toString(t)+"))";
224
return ScriptRuntime.wrapNumber(t);
228
case Id_getUTCFullYear:
230
if (id != Id_getUTCFullYear) t = LocalTime(t);
232
if (id == Id_getYear) {
233
if (cx.hasFeature(Context.FEATURE_NON_ECMA_GET_YEAR)) {
234
if (1900 <= t && t < 2000) {
242
return ScriptRuntime.wrapNumber(t);
247
if (id == Id_getMonth) t = LocalTime(t);
248
t = MonthFromTime(t);
250
return ScriptRuntime.wrapNumber(t);
255
if (id == Id_getDate) t = LocalTime(t);
258
return ScriptRuntime.wrapNumber(t);
263
if (id == Id_getDay) t = LocalTime(t);
266
return ScriptRuntime.wrapNumber(t);
271
if (id == Id_getHours) t = LocalTime(t);
274
return ScriptRuntime.wrapNumber(t);
277
case Id_getUTCMinutes:
279
if (id == Id_getMinutes) t = LocalTime(t);
282
return ScriptRuntime.wrapNumber(t);
285
case Id_getUTCSeconds:
287
if (id == Id_getSeconds) t = LocalTime(t);
290
return ScriptRuntime.wrapNumber(t);
292
case Id_getMilliseconds:
293
case Id_getUTCMilliseconds:
295
if (id == Id_getMilliseconds) t = LocalTime(t);
298
return ScriptRuntime.wrapNumber(t);
300
case Id_getTimezoneOffset:
302
t = (t - LocalTime(t)) / msPerMinute;
304
return ScriptRuntime.wrapNumber(t);
307
t = TimeClip(ScriptRuntime.toNumber(args, 0));
309
return ScriptRuntime.wrapNumber(t);
311
case Id_setMilliseconds:
312
case Id_setUTCMilliseconds:
314
case Id_setUTCSeconds:
316
case Id_setUTCMinutes:
319
t = makeTime(t, args, id);
321
return ScriptRuntime.wrapNumber(t);
328
case Id_setUTCFullYear:
329
t = makeDate(t, args, id);
331
return ScriptRuntime.wrapNumber(t);
335
double year = ScriptRuntime.toNumber(args, 0);
337
if (year != year || Double.isInfinite(year)) {
338
t = ScriptRuntime.NaN;
346
if (year >= 0 && year <= 99)
349
double day = MakeDay(year, MonthFromTime(t),
351
t = MakeDate(day, TimeWithinDay(t));
357
return ScriptRuntime.wrapNumber(t);
359
default: throw new IllegalArgumentException(String.valueOf(id));
364
/* ECMA helper functions */
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);
378
private static double Day(double t)
380
return Math.floor(t / msPerDay);
383
private static double TimeWithinDay(double t)
386
result = t % msPerDay;
392
private static boolean IsLeapYear(int year)
394
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
397
/* math here has to be f.p, because we need
398
* floor((1968 - 1969) / 4) == -1
400
private static double DayFromYear(double y)
402
return ((365 * ((y)-1970) + Math.floor(((y)-1969)/4.0)
403
- Math.floor(((y)-1901)/100.0) + Math.floor(((y)-1601)/400.0)));
406
private static double TimeFromYear(double y)
408
return DayFromYear(y) * msPerDay;
411
private static int YearFromTime(double t)
413
int lo = (int) Math.floor((t / msPerDay) / 366) + 1970;
414
int hi = (int) Math.floor((t / msPerDay) / 365) + 1970;
417
/* above doesn't work for negative dates... */
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
432
if (TimeFromYear(mid) > t) {
436
if (TimeFromYear(lo) > t) {
444
private static boolean InLeapYear(double t)
446
return IsLeapYear(YearFromTime(t));
449
private static double DayFromMonth(int m, int year)
453
if (m >= 7) { day += m / 2 - 1; }
454
else if (m >= 2) { day += (m - 1) / 2 - 1; }
457
if (m >= 2 && IsLeapYear(year)) { ++day; }
462
private static int MonthFromTime(double t)
464
int year = YearFromTime(t);
465
int d = (int)(Day(t) - DayFromYear(year));
469
return (d < -28) ? 0 : 1;
472
if (IsLeapYear(year)) {
474
return 1; // 29 February
478
// d: date count from 1 March
479
int estimate = d / 30; // approx number of month since March
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();
495
// if d < mstart then real month since March == estimate - 1
496
return (d >= mstart) ? estimate + 2 : estimate + 1;
499
private static int DateFromTime(double t)
501
int year = YearFromTime(t);
502
int d = (int)(Day(t) - DayFromYear(year));
506
return (d < -28) ? d + 31 + 28 + 1 : d + 28 + 1;
509
if (IsLeapYear(year)) {
511
return 29; // 29 February
515
// d: date count from 1 March
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;
529
return d - (31+30+31+30+31+31+30+31+30) + 1; //Late december
530
default: throw Kit.codeBug();
534
// wrong estimate: sfhift to previous month
540
private static int WeekDay(double t)
550
private static double now()
552
return (double) System.currentTimeMillis();
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.
562
private final static boolean TZO_WORKAROUND = false;
563
private static double DaylightSavingTA(double t)
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));
574
if (!TZO_WORKAROUND) {
575
Date date = new Date((long) t);
576
if (thisTimeZone.inDaylightTime(date))
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.
588
// Hardcode the assumption that the changeover always
589
// happens at 2:00 AM:
590
t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);
592
int year = YearFromTime(t);
593
double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0,
598
(int)TimeWithinDay(t));
600
if ((offset - LocalTZA) != 0)
604
// return offset - LocalTZA;
609
* Find a year for which any given date will fall on the same weekday.
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.
615
private static int EquivalentYear(int year)
617
int day = (int) DayFromYear(year) + 4;
621
// Years and leap years on which Jan 1 is a Sunday, Monday, etc.
622
if (IsLeapYear(year)) {
647
private static double LocalTime(double t)
649
return t + LocalTZA + DaylightSavingTA(t);
652
private static double internalUTC(double t)
654
return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
657
private static int HourFromTime(double t)
660
result = Math.floor(t / msPerHour) % HoursPerDay;
662
result += HoursPerDay;
666
private static int MinFromTime(double t)
669
result = Math.floor(t / msPerMinute) % MinutesPerHour;
671
result += MinutesPerHour;
675
private static int SecFromTime(double t)
678
result = Math.floor(t / msPerSecond) % SecondsPerMinute;
680
result += SecondsPerMinute;
684
private static int msFromTime(double t)
687
result = t % msPerSecond;
689
result += msPerSecond;
693
private static double MakeTime(double hour, double min,
694
double sec, double ms)
696
return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)
700
private static double MakeDay(double year, double month, double date)
702
year += Math.floor(month / 12);
708
double yearday = Math.floor(TimeFromYear(year) / msPerDay);
709
double monthday = DayFromMonth((int)month, (int)year);
711
return yearday + monthday + date - 1;
714
private static double MakeDate(double day, double time)
716
return day * msPerDay + time;
719
private static double TimeClip(double d)
722
d == Double.POSITIVE_INFINITY ||
723
d == Double.NEGATIVE_INFINITY ||
724
Math.abs(d) > HalfTimeDomain)
726
return ScriptRuntime.NaN;
729
return Math.floor(d + 0.);
731
return Math.ceil(d + 0.);
734
/* end of ECMA helper functions */
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,
746
day = MakeDay(year, mon, mday);
747
time = MakeTime(hour, min, sec, msec);
748
result = MakeDate(day, time);
753
private static final int MAXARGS = 7;
754
private static double jsStaticFunction_UTC(Object[] args)
756
double array[] = new double[MAXARGS];
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;
766
array[loop] = ScriptRuntime.toInteger(args[loop]);
772
/* adjust 2-digit years into the 20th century */
773
if (array[0] >= 0 && array[0] <= 99)
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) */
781
d = date_msecFromDate(array[0], array[1], array[2],
782
array[3], array[4], array[5], array[6]);
787
private static double date_parseString(String s)
799
double tzoffset = -1;
802
boolean seenplusminus = false;
808
if (c <= ' ' || c == ',' || c == '-') {
811
if (c == '-' && '0' <= si && si <= '9') {
817
if (c == '(') { /* comments) */
830
if ('0' <= c && c <= '9') {
832
while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
833
n = n * 10 + c - '0';
837
/* allow TZA before the year, so
838
* 'Wed Nov 05 21:49:11 GMT-0800 1997'
841
/* uses of seenplusminus allow : in TZA, so Java
842
* no-timezone style of GMT+4:30 works
844
if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
845
/* make ':' case below change tzoffset */
846
seenplusminus = true;
850
n = n * 60; /* EG. "GMT-3" */
852
n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
853
if (prevc == '+') /* plus means east of GMT */
855
if (tzoffset != 0 && tzoffset != -1)
856
return ScriptRuntime.NaN;
858
} else if (n >= 70 ||
859
(prevc == '/' && mon >= 0 && mday >= 0
863
return ScriptRuntime.NaN;
864
else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
865
year = n < 100 ? n + 1900 : n;
867
return ScriptRuntime.NaN;
868
} else if (c == ':') {
874
return ScriptRuntime.NaN;
875
} else if (c == '/') {
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 */
889
} else if (hour >= 0 && min < 0) {
891
} else if (min >= 0 && sec < 0) {
893
} else if (mday < 0) {
896
return ScriptRuntime.NaN;
899
} else if (c == '/' || c == ':' || c == '+' || c == '-') {
905
if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
909
int letterCount = i - st;
911
return ScriptRuntime.NaN;
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?
917
String wtb = "am;pm;"
918
+"monday;tuesday;wednesday;thursday;friday;"
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;";
924
for (int wtbOffset = 0; ;) {
925
int wtbNext = wtb.indexOf(';', wtbOffset);
927
return ScriptRuntime.NaN;
928
if (wtb.regionMatches(true, wtbOffset, s, st, letterCount))
930
wtbOffset = wtbNext + 1;
935
* AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
936
* 12:30, instead of blindly adding 12 if PM.
938
if (hour > 12 || hour < 0) {
939
return ScriptRuntime.NaN;
940
} else if (index == 0) {
949
} else if ((index -= 2) < 7) {
951
} else if ((index -= 7) < 12) {
956
return ScriptRuntime.NaN;
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();
978
if (year < 0 || mon < 0 || mday < 0)
979
return ScriptRuntime.NaN;
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);
991
return msec + tzoffset * msPerMinute;
995
private static String date_format(double t, int methodId)
997
StringBuffer result = new StringBuffer(60);
998
double local = LocalTime(t);
1000
/* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
1001
/* Tue Oct 31 2000 */
1002
/* 09:41:40 GMT-0800 (PST) */
1004
if (methodId != Id_toTimeString) {
1005
appendWeekDayName(result, WeekDay(local));
1007
appendMonthName(result, MonthFromTime(local));
1009
append0PaddedUint(result, DateFromTime(local), 2);
1011
int year = YearFromTime(local);
1016
append0PaddedUint(result, year, 4);
1017
if (methodId != Id_toDateString)
1021
if (methodId != Id_toDateString) {
1022
append0PaddedUint(result, HourFromTime(local), 2);
1024
append0PaddedUint(result, MinFromTime(local), 2);
1026
append0PaddedUint(result, SecFromTime(local), 2);
1028
// offset from GMT in minutes. The offset includes daylight
1029
// savings, if it applies.
1030
int minutes = (int) Math.floor((LocalTZA + DaylightSavingTA(t))
1032
// map 510 minutes to 0830 hours
1033
int offset = (minutes / 60) * 100 + minutes % 60;
1035
result.append(" GMT+");
1037
result.append(" GMT-");
1040
append0PaddedUint(result, offset, 4);
1042
if (timeZoneFormatter == null)
1043
timeZoneFormatter = new java.text.SimpleDateFormat("zzz");
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));
1052
result.append(" (");
1053
java.util.Date date = new Date((long) t);
1054
result.append(timeZoneFormatter.format(date));
1057
return result.toString();
1060
/* the javascript constructor */
1061
private static Object jsConstructor(Object[] args)
1063
NativeDate obj = new NativeDate();
1065
// if called as a constructor with no args,
1066
// return a new Date with the current time.
1067
if (args.length == 0) {
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);
1078
if (arg0 instanceof String) {
1079
// it's a string; parse it.
1080
date = date_parseString((String)arg0);
1082
// if it's not a string, use it as a millisecond date
1083
date = ScriptRuntime.toNumber(arg0);
1085
obj.date = TimeClip(date);
1089
// multiple arguments; year, month, day etc.
1090
double array[] = new double[MAXARGS];
1094
for (loop = 0; loop < MAXARGS; loop++) {
1095
if (loop < args.length) {
1096
d = ScriptRuntime.toNumber(args[loop]);
1098
if (d != d || Double.isInfinite(d)) {
1099
obj.date = ScriptRuntime.NaN;
1102
array[loop] = ScriptRuntime.toInteger(args[loop]);
1108
/* adjust 2-digit years into the 20th century */
1109
if (array[0] >= 0 && array[0] <= 99)
1112
/* if we got a 0 for 'date' (which is out of range)
1113
* pretend it's a 1 */
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);
1126
private static String toLocale_helper(double t, int methodId)
1128
java.text.DateFormat formatter;
1130
case Id_toLocaleString:
1131
if (localeDateTimeFormatter == null) {
1132
localeDateTimeFormatter
1133
= DateFormat.getDateTimeInstance(DateFormat.LONG,
1136
formatter = localeDateTimeFormatter;
1138
case Id_toLocaleTimeString:
1139
if (localeTimeFormatter == null) {
1141
= DateFormat.getTimeInstance(DateFormat.LONG);
1143
formatter = localeTimeFormatter;
1145
case Id_toLocaleDateString:
1146
if (localeDateFormatter == null) {
1148
= DateFormat.getDateInstance(DateFormat.LONG);
1150
formatter = localeDateFormatter;
1152
default: formatter = null; // unreachable
1155
return formatter.format(new Date((long) t));
1158
private static String js_toUTCString(double date)
1160
StringBuffer result = new StringBuffer(60);
1162
appendWeekDayName(result, WeekDay(date));
1163
result.append(", ");
1164
append0PaddedUint(result, DateFromTime(date), 2);
1166
appendMonthName(result, MonthFromTime(date));
1168
int year = YearFromTime(date);
1170
result.append('-'); year = -year;
1172
append0PaddedUint(result, year, 4);
1174
append0PaddedUint(result, HourFromTime(date), 2);
1176
append0PaddedUint(result, MinFromTime(date), 2);
1178
append0PaddedUint(result, SecFromTime(date), 2);
1179
result.append(" GMT");
1180
return result.toString();
1183
private static void append0PaddedUint(StringBuffer sb, int i, int minWidth)
1185
if (i < 0) Kit.codeBug();
1189
if (i < 1000 * 1000 * 1000) {
1191
int newScale = scale * 10;
1192
if (i < newScale) { break; }
1197
// Separated case not to check against 10 * 10^9 overflow
1199
scale = 1000 * 1000 * 1000;
1202
while (minWidth > 0) {
1206
while (scale != 1) {
1207
sb.append((char)('0' + (i / scale)));
1211
sb.append((char)('0' + i));
1214
private static void appendMonthName(StringBuffer sb, int index)
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";
1222
for (int i = 0; i != 3; ++i) {
1223
sb.append(months.charAt(index + i));
1227
private static void appendWeekDayName(StringBuffer sb, int index)
1229
String days = "Sun"+"Mon"+"Tue"+"Wed"+"Thu"+"Fri"+"Sat";
1231
for (int i = 0; i != 3; ++i) {
1232
sb.append(days.charAt(index + i));
1236
private static double makeTime(double date, Object[] args, int methodId)
1239
boolean local = true;
1241
case Id_setUTCMilliseconds:
1244
case Id_setMilliseconds:
1248
case Id_setUTCSeconds:
1255
case Id_setUTCMinutes:
1262
case Id_setUTCHours:
1275
double conv[] = new double[4];
1276
double hour, min, sec, msec;
1277
double lorutime; /* Local or UTC version of date */
1282
/* just return NaN if the date is already NaN */
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.
1294
if (args.length == 0)
1295
args = ScriptRuntime.padArguments(args, 1);
1297
for (i = 0; i < args.length && i < maxargs; i++) {
1298
conv[i] = ScriptRuntime.toNumber(args[i]);
1300
// limit checks that happen in MakeTime in ECMA.
1301
if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1302
return ScriptRuntime.NaN;
1304
conv[i] = ScriptRuntime.toInteger(conv[i]);
1308
lorutime = LocalTime(date);
1313
int stop = args.length;
1315
if (maxargs >= 4 && i < stop)
1318
hour = HourFromTime(lorutime);
1320
if (maxargs >= 3 && i < stop)
1323
min = MinFromTime(lorutime);
1325
if (maxargs >= 2 && i < stop)
1328
sec = SecFromTime(lorutime);
1330
if (maxargs >= 1 && i < stop)
1333
msec = msFromTime(lorutime);
1335
time = MakeTime(hour, min, sec, msec);
1336
result = MakeDate(Day(lorutime), time);
1339
result = internalUTC(result);
1340
date = TimeClip(result);
1345
private static double makeDate(double date, Object[] args, int methodId)
1348
boolean local = true;
1357
case Id_setUTCMonth:
1364
case Id_setUTCFullYear:
1367
case Id_setFullYear:
1377
double conv[] = new double[3];
1378
double year, month, day;
1379
double lorutime; /* local or UTC version of date */
1382
/* See arg padding comment in makeTime.*/
1383
if (args.length == 0)
1384
args = ScriptRuntime.padArguments(args, 1);
1386
for (i = 0; i < args.length && i < maxargs; i++) {
1387
conv[i] = ScriptRuntime.toNumber(args[i]);
1389
// limit checks that happen in MakeDate in ECMA.
1390
if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1391
return ScriptRuntime.NaN;
1393
conv[i] = ScriptRuntime.toInteger(conv[i]);
1396
/* return NaN if date is NaN and we're not setting the year,
1397
* If we are, use 0 as the time. */
1399
if (args.length < 3) {
1400
return ScriptRuntime.NaN;
1406
lorutime = LocalTime(date);
1412
int stop = args.length;
1414
if (maxargs >= 3 && i < stop)
1417
year = YearFromTime(lorutime);
1419
if (maxargs >= 2 && i < stop)
1422
month = MonthFromTime(lorutime);
1424
if (maxargs >= 1 && i < stop)
1427
day = DateFromTime(lorutime);
1429
day = MakeDay(year, month, day); /* day within year */
1430
result = MakeDate(day, TimeWithinDay(lorutime));
1433
result = internalUTC(result);
1435
date = TimeClip(result);
1442
protected int findPrototypeId(String s)
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; }
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; }
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; }
1462
case 'u': X="valueOf";id=Id_valueOf; 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; }
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; }
1473
case 'o': X="toSource";id=Id_toSource; break L;
1474
case 't': X="toString";id=Id_toString; break L;
1476
case 9: X="getUTCDay";id=Id_getUTCDay; break L;
1477
case 10: c=s.charAt(3);
1480
if (c=='g') { X="getMinutes";id=Id_getMinutes; }
1481
else if (c=='s') { X="setMinutes";id=Id_setMinutes; }
1485
if (c=='g') { X="getSeconds";id=Id_getSeconds; }
1486
else if (c=='s') { X="setSeconds";id=Id_setSeconds; }
1490
if (c=='g') { X="getUTCDate";id=Id_getUTCDate; }
1491
else if (c=='s') { X="setUTCDate";id=Id_setUTCDate; }
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; }
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);
1504
if (c=='r') { X="getUTCHours";id=Id_getUTCHours; }
1505
else if (c=='t') { X="getUTCMonth";id=Id_getUTCMonth; }
1509
if (c=='r') { X="setUTCHours";id=Id_setUTCHours; }
1510
else if (c=='t') { X="setUTCMonth";id=Id_setUTCMonth; }
1513
case 's': X="constructor";id=Id_constructor; 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; }
1519
case 13: c=s.charAt(0);
1522
if (c=='M') { X="getUTCMinutes";id=Id_getUTCMinutes; }
1523
else if (c=='S') { X="getUTCSeconds";id=Id_getUTCSeconds; }
1527
if (c=='M') { X="setUTCMinutes";id=Id_setUTCMinutes; }
1528
else if (c=='S') { X="setUTCSeconds";id=Id_setUTCSeconds; }
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; }
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; }
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; }
1546
if (c=='D') { X="toLocaleDateString";id=Id_toLocaleDateString; }
1547
else if (c=='T') { X="toLocaleTimeString";id=Id_toLocaleTimeString; }
1551
if (X!=null && X!=s && !X.equals(s)) id = 0;
1557
private static final int
1558
ConstructorId_now = -3,
1559
ConstructorId_parse = -2,
1560
ConstructorId_UTC = -1,
1564
Id_toTimeString = 3,
1565
Id_toDateString = 4,
1566
Id_toLocaleString = 5,
1567
Id_toLocaleTimeString = 6,
1568
Id_toLocaleDateString = 7,
1574
Id_getFullYear = 13,
1575
Id_getUTCFullYear = 14,
1577
Id_getUTCMonth = 16,
1583
Id_getUTCHours = 22,
1585
Id_getUTCMinutes = 24,
1587
Id_getUTCSeconds = 26,
1588
Id_getMilliseconds = 27,
1589
Id_getUTCMilliseconds = 28,
1590
Id_getTimezoneOffset = 29,
1592
Id_setMilliseconds = 31,
1593
Id_setUTCMilliseconds = 32,
1595
Id_setUTCSeconds = 34,
1597
Id_setUTCMinutes = 36,
1599
Id_setUTCHours = 38,
1603
Id_setUTCMonth = 42,
1604
Id_setFullYear = 43,
1605
Id_setUTCFullYear = 44,
1608
MAX_PROTOTYPE_ID = 45;
1610
private static final int
1611
Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6
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;
1622
private double date;