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.
39 import java.util.TimeZone;
40 import java.util.Locale;
41 import java.text.NumberFormat;
42 import java.text.DateFormat;
43 import java.text.SimpleDateFormat;
46 * This class implements the Date native object.
50 public class Date extends JS.Obj {
53 if (thisTimeZone == null) {
54 // j.u.TimeZone is synchronized, so setting class statics from it
56 thisTimeZone = java.util.TimeZone.getDefault();
57 LocalTZA = thisTimeZone.getRawOffset();
61 public String coerceToString() { return date_format(date, FORMATSPEC_FULL); }
63 public Object callMethod(Object name, JS.Array args_, boolean checkOnly) {
64 Object[] args = new Object[args_.length()];
65 for(int i=0; i<args.length; i++) args[i] = args_.elementAt(i);
67 if (name.equals(getIdName(ConstructorId_UTC))) {
68 if (checkOnly) return Boolean.TRUE;
69 return new Double(jsStaticFunction_UTC(args));
71 } else if (name.equals(getIdName(ConstructorId_parse))) {
72 if (checkOnly) return Boolean.TRUE;
73 return new Double(jsStaticFunction_parse(args[0].toString()));
75 } else if (name.equals(getIdName(Id_constructor))) {
76 if (checkOnly) return Boolean.TRUE;
77 return new Date(args_);
79 } else if (name.equals(getIdName(Id_toString))) {
80 if (checkOnly) return Boolean.TRUE;
82 return date_format(t, FORMATSPEC_FULL);
84 } else if (name.equals(getIdName(Id_toTimeString))) {
85 if (checkOnly) return Boolean.TRUE;
87 return date_format(t, FORMATSPEC_TIME);
89 } else if (name.equals(getIdName(Id_toDateString))) {
90 if (checkOnly) return Boolean.TRUE;
92 return date_format(t, FORMATSPEC_DATE);
94 } else if (name.equals(getIdName(Id_toLocaleString))) {
95 if (checkOnly) return Boolean.TRUE;
97 return jsFunction_toLocaleString(t);
99 } else if (name.equals(getIdName(Id_toLocaleTimeString))) {
100 if (checkOnly) return Boolean.TRUE;
102 return jsFunction_toLocaleTimeString(t);
104 } else if (name.equals(getIdName(Id_toLocaleDateString))) {
105 if (checkOnly) return Boolean.TRUE;
107 return jsFunction_toLocaleDateString(t);
109 } else if (name.equals(getIdName(Id_toUTCString))) {
110 if (checkOnly) return Boolean.TRUE;
112 return jsFunction_toUTCString(t);
114 } else if (name.equals(getIdName(Id_valueOf))) {
115 if (checkOnly) return Boolean.TRUE;
116 return new Double(this.date);
118 } else if (name.equals(getIdName(Id_getTime))) {
119 if (checkOnly) return Boolean.TRUE;
120 return new Double(this.date);
122 } else if (name.equals(getIdName(Id_getYear))) {
123 if (checkOnly) return Boolean.TRUE;
125 t = jsFunction_getYear(t);
126 return new Double(t);
128 } else if (name.equals(getIdName(Id_getFullYear))) {
129 if (checkOnly) return Boolean.TRUE;
131 t = YearFromTime(LocalTime(t));
132 return new Double(t);
134 } else if (name.equals(getIdName(Id_getUTCFullYear))) {
135 if (checkOnly) return Boolean.TRUE;
138 return new Double(t);
140 } else if (name.equals(getIdName(Id_getMonth))) {
141 if (checkOnly) return Boolean.TRUE;
143 t = MonthFromTime(LocalTime(t));
144 return new Double(t);
146 } else if (name.equals(getIdName(Id_getUTCMonth))) {
147 if (checkOnly) return Boolean.TRUE;
149 t = MonthFromTime(t);
150 return new Double(t);
152 } else if (name.equals(getIdName(Id_getDate))) {
153 if (checkOnly) return Boolean.TRUE;
155 t = DateFromTime(LocalTime(t));
156 return new Double(t);
158 } else if (name.equals(getIdName(Id_getUTCDate))) {
159 if (checkOnly) return Boolean.TRUE;
162 return new Double(t);
164 } else if (name.equals(getIdName(Id_getDay))) {
165 if (checkOnly) return Boolean.TRUE;
167 t = WeekDay(LocalTime(t));
168 return new Double(t);
170 } else if (name.equals(getIdName(Id_getUTCDay))) {
171 if (checkOnly) return Boolean.TRUE;
174 return new Double(t);
176 } else if (name.equals(getIdName(Id_getHours))) {
177 if (checkOnly) return Boolean.TRUE;
179 t = HourFromTime(LocalTime(t));
180 return new Double(t);
182 } else if (name.equals(getIdName(Id_getUTCHours))) {
183 if (checkOnly) return Boolean.TRUE;
186 return new Double(t);
188 } else if (name.equals(getIdName(Id_getMinutes))) {
189 if (checkOnly) return Boolean.TRUE;
191 t = MinFromTime(LocalTime(t));
192 return new Double(t);
194 } else if (name.equals(getIdName(Id_getUTCMinutes))) {
195 if (checkOnly) return Boolean.TRUE;
198 return new Double(t);
200 } else if (name.equals(getIdName(Id_getSeconds))) {
201 if (checkOnly) return Boolean.TRUE;
203 t = SecFromTime(LocalTime(t));
204 return new Double(t);
206 } else if (name.equals(getIdName(Id_getUTCSeconds))) {
207 if (checkOnly) return Boolean.TRUE;
210 return new Double(t);
212 } else if (name.equals(getIdName(Id_getMilliseconds))) {
213 if (checkOnly) return Boolean.TRUE;
215 t = msFromTime(LocalTime(t));
216 return new Double(t);
218 } else if (name.equals(getIdName(Id_getUTCMilliseconds))) {
219 if (checkOnly) return Boolean.TRUE;
222 return new Double(t);
224 } else if (name.equals(getIdName(Id_getTimezoneOffset))) {
225 if (checkOnly) return Boolean.TRUE;
227 t = jsFunction_getTimezoneOffset(t);
228 return new Double(t);
230 } else if (name.equals(getIdName(Id_setTime))) {
231 if (checkOnly) return Boolean.TRUE;
232 return new Double(this.jsFunction_setTime(_toNumber(args, 0)));
234 } else if (name.equals(getIdName(Id_setMilliseconds))) {
235 if (checkOnly) return Boolean.TRUE;
236 return new Double(this.
237 makeTime(args, 1, true));
239 } else if (name.equals(getIdName(Id_setUTCMilliseconds))) {
240 if (checkOnly) return Boolean.TRUE;
241 return new Double(this.
242 makeTime(args, 1, false));
244 } else if (name.equals(getIdName(Id_setSeconds))) {
245 if (checkOnly) return Boolean.TRUE;
246 return new Double(this.
247 makeTime(args, 2, true));
249 } else if (name.equals(getIdName(Id_setUTCSeconds))) {
250 if (checkOnly) return Boolean.TRUE;
251 return new Double(this.
252 makeTime(args, 2, false));
254 } else if (name.equals(getIdName(Id_setMinutes))) {
255 if (checkOnly) return Boolean.TRUE;
256 return new Double(this.
257 makeTime(args, 3, true));
259 } else if (name.equals(getIdName(Id_setUTCMinutes))) {
260 if (checkOnly) return Boolean.TRUE;
261 return new Double(this.
262 makeTime(args, 3, false));
264 } else if (name.equals(getIdName(Id_setHours))) {
265 if (checkOnly) return Boolean.TRUE;
266 return new Double(this.
267 makeTime(args, 4, true));
269 } else if (name.equals(getIdName(Id_setUTCHours))) {
270 if (checkOnly) return Boolean.TRUE;
271 return new Double(this.
272 makeTime(args, 4, false));
274 } else if (name.equals(getIdName(Id_setDate))) {
275 if (checkOnly) return Boolean.TRUE;
276 return new Double(this.
277 makeDate(args, 1, true));
279 } else if (name.equals(getIdName(Id_setUTCDate))) {
280 if (checkOnly) return Boolean.TRUE;
281 return new Double(this.
282 makeDate(args, 1, false));
284 } else if (name.equals(getIdName(Id_setMonth))) {
285 if (checkOnly) return Boolean.TRUE;
286 return new Double(this.
287 makeDate(args, 2, true));
289 } else if (name.equals(getIdName(Id_setUTCMonth))) {
290 if (checkOnly) return Boolean.TRUE;
291 return new Double(this.
292 makeDate(args, 2, false));
294 } else if (name.equals(getIdName(Id_setFullYear))) {
295 if (checkOnly) return Boolean.TRUE;
296 return new Double(this.
297 makeDate(args, 3, true));
299 } else if (name.equals(getIdName(Id_setUTCFullYear))) {
300 if (checkOnly) return Boolean.TRUE;
301 return new Double(this.
302 makeDate(args, 3, false));
304 } else if (name.equals(getIdName(Id_setYear))) {
305 if (checkOnly) return Boolean.TRUE;
306 return new Double(this.
307 jsFunction_setYear(_toNumber(args, 0)));
309 if (checkOnly) return Boolean.FALSE;
313 /* ECMA helper functions */
315 private static final double HalfTimeDomain = 8.64e15;
316 private static final double HoursPerDay = 24.0;
317 private static final double MinutesPerHour = 60.0;
318 private static final double SecondsPerMinute = 60.0;
319 private static final double msPerSecond = 1000.0;
320 private static final double MinutesPerDay = (HoursPerDay * MinutesPerHour);
321 private static final double SecondsPerDay = (MinutesPerDay * SecondsPerMinute);
322 private static final double SecondsPerHour = (MinutesPerHour * SecondsPerMinute);
323 private static final double msPerDay = (SecondsPerDay * msPerSecond);
324 private static final double msPerHour = (SecondsPerHour * msPerSecond);
325 private static final double msPerMinute = (SecondsPerMinute * msPerSecond);
327 private static double Day(double t) {
328 return java.lang.Math.floor(t / msPerDay);
331 private static double TimeWithinDay(double t) {
333 result = t % msPerDay;
339 private static int DaysInYear(int y) {
340 if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
347 /* math here has to be f.p, because we need
348 * floor((1968 - 1969) / 4) == -1
350 private static double DayFromYear(double y) {
351 return ((365 * ((y)-1970) + java.lang.Math.floor(((y)-1969)/4.0)
352 - java.lang.Math.floor(((y)-1901)/100.0) + java.lang.Math.floor(((y)-1601)/400.0)));
355 private static double TimeFromYear(double y) {
356 return DayFromYear(y) * msPerDay;
359 private static int YearFromTime(double t) {
360 int lo = (int) java.lang.Math.floor((t / msPerDay) / 366) + 1970;
361 int hi = (int) java.lang.Math.floor((t / msPerDay) / 365) + 1970;
364 /* above doesn't work for negative dates... */
371 /* Use a simple binary search algorithm to find the right
372 year. This seems like brute force... but the computation
373 of hi and lo years above lands within one year of the
374 correct answer for years within a thousand years of
375 1970; the loop below only requires six iterations
379 if (TimeFromYear(mid) > t) {
382 if (TimeFromYear(mid) <= t) {
384 if (TimeFromYear(temp) > t) {
394 private static boolean InLeapYear(double t) {
395 return DaysInYear(YearFromTime(t)) == 366;
398 private static int DayWithinYear(double t) {
399 int year = YearFromTime(t);
400 return (int) (Day(t) - DayFromYear(year));
403 * The following array contains the day of year for the first day of
404 * each month, where index 0 is January, and day 0 is January 1.
407 private static double DayFromMonth(int m, boolean leap) {
410 if (m >= 7) { day += m / 2 - 1; }
411 else if (m >= 2) { day += (m - 1) / 2 - 1; }
414 if (leap && m >= 2) { ++day; }
419 private static int MonthFromTime(double t) {
422 d = DayWithinYear(t);
427 // Originally coded as step += (InLeapYear(t) ? 29 : 28);
428 // but some jits always returned 28!
436 if (d < (step += 31))
438 if (d < (step += 30))
440 if (d < (step += 31))
442 if (d < (step += 30))
444 if (d < (step += 31))
446 if (d < (step += 31))
448 if (d < (step += 30))
450 if (d < (step += 31))
452 if (d < (step += 30))
457 private static int DateFromTime(double t) {
460 d = DayWithinYear(t);
461 if (d <= (next = 30))
465 // Originally coded as next += (InLeapYear(t) ? 29 : 28);
466 // but some jits always returned 28!
475 if (d <= (next += 31))
478 if (d <= (next += 30))
481 if (d <= (next += 31))
484 if (d <= (next += 30))
487 if (d <= (next += 31))
490 if (d <= (next += 31))
493 if (d <= (next += 30))
496 if (d <= (next += 31))
499 if (d <= (next += 30))
506 private static int WeekDay(double t) {
515 private static double Now() {
516 return (double) System.currentTimeMillis();
519 /* Should be possible to determine the need for this dynamically
520 * if we go with the workaround... I'm not using it now, because I
521 * can't think of any clean way to make toLocaleString() and the
522 * time zone (comment) in toString match the generated string
523 * values. Currently it's wrong-but-consistent in all but the
524 * most recent betas of the JRE - seems to work in 1.1.7.
526 private final static boolean TZO_WORKAROUND = false;
527 private static double DaylightSavingTA(double t) {
528 if (!TZO_WORKAROUND) {
529 java.util.Date date = new java.util.Date((long) t);
530 if (thisTimeZone.inDaylightTime(date))
535 /* Use getOffset if inDaylightTime() is broken, because it
536 * seems to work acceptably. We don't switch over to it
537 * entirely, because it requires (expensive) exploded date arguments,
538 * and the api makes it impossible to handle dst
539 * changeovers cleanly.
542 // Hardcode the assumption that the changeover always
543 // happens at 2:00 AM:
544 t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);
546 int year = YearFromTime(t);
547 double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0,
552 (int)TimeWithinDay(t));
554 if ((offset - LocalTZA) != 0)
558 // return offset - LocalTZA;
562 private static double LocalTime(double t) {
563 return t + LocalTZA + DaylightSavingTA(t);
566 public static double internalUTC(double t) {
567 return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
570 private static int HourFromTime(double t) {
572 result = java.lang.Math.floor(t / msPerHour) % HoursPerDay;
574 result += HoursPerDay;
578 private static int MinFromTime(double t) {
580 result = java.lang.Math.floor(t / msPerMinute) % MinutesPerHour;
582 result += MinutesPerHour;
586 private static int SecFromTime(double t) {
588 result = java.lang.Math.floor(t / msPerSecond) % SecondsPerMinute;
590 result += SecondsPerMinute;
594 private static int msFromTime(double t) {
596 result = t % msPerSecond;
598 result += msPerSecond;
602 private static double MakeTime(double hour, double min,
603 double sec, double ms)
605 return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)
609 private static double MakeDay(double year, double month, double date) {
615 year += java.lang.Math.floor(month / 12);
621 leap = (DaysInYear((int) year) == 366);
623 yearday = java.lang.Math.floor(TimeFromYear(year) / msPerDay);
624 monthday = DayFromMonth((int) month, leap);
632 private static double MakeDate(double day, double time) {
633 return day * msPerDay + time;
636 private static double TimeClip(double d) {
638 d == Double.POSITIVE_INFINITY ||
639 d == Double.NEGATIVE_INFINITY ||
640 java.lang.Math.abs(d) > HalfTimeDomain)
645 return java.lang.Math.floor(d + 0.);
647 return java.lang.Math.ceil(d + 0.);
650 /* end of ECMA helper functions */
652 /* find UTC time from given date... no 1900 correction! */
653 public static double date_msecFromDate(double year, double mon,
654 double mday, double hour,
655 double min, double sec,
662 day = MakeDay(year, mon, mday);
663 time = MakeTime(hour, min, sec, msec);
664 result = MakeDate(day, time);
669 private static final int MAXARGS = 7;
670 private static double jsStaticFunction_UTC(Object[] args) {
671 double array[] = new double[MAXARGS];
675 for (loop = 0; loop < MAXARGS; loop++) {
676 if (loop < args.length) {
677 d = _toNumber(args[loop]);
678 if (d != d || Double.isInfinite(d)) {
681 array[loop] = toDouble(args[loop]);
687 /* adjust 2-digit years into the 20th century */
688 if (array[0] >= 0 && array[0] <= 99)
691 /* if we got a 0 for 'date' (which is out of range)
692 * pretend it's a 1. (So Date.UTC(1972, 5) works) */
696 d = date_msecFromDate(array[0], array[1], array[2],
697 array[3], array[4], array[5], array[6]);
700 // return new Double(d);
704 * Use ported code from jsdate.c rather than the locale-specific
705 * date-parsing code from Java, to keep js and rhino consistent.
706 * Is this the right strategy?
709 /* for use by date_parse */
711 /* replace this with byte arrays? Cheaper? */
712 private static String wtb[] = {
714 "monday", "tuesday", "wednesday", "thursday", "friday",
715 "saturday", "sunday",
716 "january", "february", "march", "april", "may", "june",
717 "july", "august", "september", "october", "november", "december",
718 "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
719 "mst", "mdt", "pst", "pdt"
720 /* time zone table needs to be expanded */
723 private static int ttb[] = {
724 -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
725 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
726 10000 + 0, 10000 + 0, 10000 + 0, /* UT/UTC */
727 10000 + 5 * 60, 10000 + 4 * 60, /* EDT */
728 10000 + 6 * 60, 10000 + 5 * 60,
729 10000 + 7 * 60, 10000 + 6 * 60,
730 10000 + 8 * 60, 10000 + 7 * 60
733 /* helper for date_parse */
734 private static boolean date_regionMatches(String s1, int s1off,
735 String s2, int s2off,
738 boolean result = false;
739 /* return true if matches, otherwise, false */
740 int s1len = s1.length();
741 int s2len = s2.length();
743 while (count > 0 && s1off < s1len && s2off < s2len) {
744 if (Character.toLowerCase(s1.charAt(s1off)) !=
745 Character.toLowerCase(s2.charAt(s2off)))
758 private static double date_parseString(String s) {
771 double tzoffset = -1;
774 boolean seenplusminus = false;
776 if (s == null) // ??? Will s be null?
782 if (c <= ' ' || c == ',' || c == '-') {
785 if (c == '-' && '0' <= si && si <= '9') {
791 if (c == '(') { /* comments) */
804 if ('0' <= c && c <= '9') {
806 while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
807 n = n * 10 + c - '0';
811 /* allow TZA before the year, so
812 * 'Wed Nov 05 21:49:11 GMT-0800 1997'
815 /* uses of seenplusminus allow : in TZA, so Java
816 * no-timezone style of GMT+4:30 works
818 if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
819 /* make ':' case below change tzoffset */
820 seenplusminus = true;
824 n = n * 60; /* EG. "GMT-3" */
826 n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
827 if (prevc == '+') /* plus means east of GMT */
829 if (tzoffset != 0 && tzoffset != -1)
832 } else if (n >= 70 ||
833 (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
836 else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
837 year = n < 100 ? n + 1900 : n;
840 } else if (c == ':') {
847 } else if (c == '/') {
854 } else if (i < limit && c != ',' && c > ' ' && c != '-') {
856 } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
861 } else if (hour >= 0 && min < 0) {
863 } else if (min >= 0 && sec < 0) {
865 } else if (mday < 0) {
871 } else if (c == '/' || c == ':' || c == '+' || c == '-') {
878 if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
884 for (k = wtb.length; --k >= 0;)
885 if (date_regionMatches(wtb[k], 0, s, st, i-st)) {
890 * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
891 * 12:30, instead of blindly adding 12 if PM.
893 if (hour > 12 || hour < 0) {
896 if (action == -1 && hour == 12) { // am
898 } else if (action == -2 && hour != 12) {// pm
902 } else if (action <= 13) { /* month! */
904 mon = /*byte*/ (action - 2);
909 tzoffset = action - 10000;
919 if (year < 0 || mon < 0 || mday < 0)
927 if (tzoffset == -1) { /* no time zone specified, have to use local */
929 time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
930 return internalUTC(time);
933 msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
934 msec += tzoffset * msPerMinute;
938 private static double jsStaticFunction_parse(String s) {
939 return date_parseString(s);
942 private static final int FORMATSPEC_FULL = 0;
943 private static final int FORMATSPEC_DATE = 1;
944 private static final int FORMATSPEC_TIME = 2;
946 private static String date_format(double t, int format) {
948 return jsFunction_NaN_date_str;
950 StringBuffer result = new StringBuffer(60);
951 double local = LocalTime(t);
953 /* offset from GMT in minutes. The offset includes daylight savings,
955 int minutes = (int) java.lang.Math.floor((LocalTZA + DaylightSavingTA(t))
957 /* map 510 minutes to 0830 hours */
958 int offset = (minutes / 60) * 100 + minutes % 60;
960 String dateStr = Integer.toString(DateFromTime(local));
961 String hourStr = Integer.toString(HourFromTime(local));
962 String minStr = Integer.toString(MinFromTime(local));
963 String secStr = Integer.toString(SecFromTime(local));
964 String offsetStr = Integer.toString(offset > 0 ? offset : -offset);
965 int year = YearFromTime(local);
966 String yearStr = Integer.toString(year > 0 ? year : -year);
968 /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
969 /* Tue Oct 31 2000 */
970 /* 09:41:40 GMT-0800 (PST) */
972 if (format != FORMATSPEC_TIME) {
973 result.append(days[WeekDay(local)]);
975 result.append(months[MonthFromTime(local)]);
976 if (dateStr.length() == 1)
980 result.append(dateStr);
984 if (format != FORMATSPEC_DATE) {
985 if (hourStr.length() == 1)
987 result.append(hourStr);
988 if (minStr.length() == 1)
992 result.append(minStr);
993 if (secStr.length() == 1)
997 result.append(secStr);
999 result.append(" GMT+");
1001 result.append(" GMT-");
1002 for (int i = offsetStr.length(); i < 4; i++)
1004 result.append(offsetStr);
1006 if (timeZoneFormatter == null)
1007 timeZoneFormatter = new java.text.SimpleDateFormat("zzz");
1009 if (timeZoneFormatter != null) {
1010 result.append(" (");
1011 java.util.Date date = new java.util.Date((long) t);
1012 result.append(timeZoneFormatter.format(date));
1015 if (format != FORMATSPEC_TIME)
1019 if (format != FORMATSPEC_TIME) {
1022 for (int i = yearStr.length(); i < 4; i++)
1024 result.append(yearStr);
1027 return result.toString();
1030 private static double _toNumber(Object o) { return JS.toDouble(o); }
1031 private static double _toNumber(Object[] o, int index) { return JS.toDouble(o[index]); }
1032 private static double toDouble(double d) { return d; }
1034 public Date(JS.Array args_) {
1035 Object[] args = new Object[args_.length()];
1036 for(int i=0; i<args.length; i++) args[i] = args_.elementAt(i);
1039 // if called as a constructor with no args,
1040 // return a new Date with the current time.
1041 if (args.length == 0) {
1046 // if called with just one arg -
1047 if (args.length == 1) {
1049 if (args[0] instanceof JS)
1050 args[0] = ((JS) args[0]).toString();
1051 if (!(args[0] instanceof String)) {
1052 // if it's not a string, use it as a millisecond date
1053 date = _toNumber(args[0]);
1055 // it's a string; parse it.
1056 String str = (String) args[0];
1057 date = date_parseString(str);
1059 obj.date = TimeClip(date);
1063 // multiple arguments; year, month, day etc.
1064 double array[] = new double[MAXARGS];
1068 for (loop = 0; loop < MAXARGS; loop++) {
1069 if (loop < args.length) {
1070 d = _toNumber(args[loop]);
1072 if (d != d || Double.isInfinite(d)) {
1073 obj.date = Double.NaN;
1076 array[loop] = toDouble(args[loop]);
1082 /* adjust 2-digit years into the 20th century */
1083 if (array[0] >= 0 && array[0] <= 99)
1086 /* if we got a 0 for 'date' (which is out of range)
1087 * pretend it's a 1 */
1091 double day = MakeDay(array[0], array[1], array[2]);
1092 double time = MakeTime(array[3], array[4], array[5], array[6]);
1093 time = MakeDate(day, time);
1094 time = internalUTC(time);
1095 obj.date = TimeClip(time);
1100 /* constants for toString, toUTCString */
1101 private static String jsFunction_NaN_date_str = "Invalid Date";
1103 private static String[] days = {
1104 "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
1107 private static String[] months = {
1108 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1109 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1112 private static String toLocale_helper(double t,
1113 java.text.DateFormat formatter)
1116 return jsFunction_NaN_date_str;
1118 java.util.Date tempdate = new java.util.Date((long) t);
1119 return formatter.format(tempdate);
1122 private static String jsFunction_toLocaleString(double date) {
1123 if (localeDateTimeFormatter == null)
1124 localeDateTimeFormatter =
1125 DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
1127 return toLocale_helper(date, localeDateTimeFormatter);
1130 private static String jsFunction_toLocaleTimeString(double date) {
1131 if (localeTimeFormatter == null)
1132 localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG);
1134 return toLocale_helper(date, localeTimeFormatter);
1137 private static String jsFunction_toLocaleDateString(double date) {
1138 if (localeDateFormatter == null)
1139 localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG);
1141 return toLocale_helper(date, localeDateFormatter);
1144 private static String jsFunction_toUTCString(double date) {
1145 StringBuffer result = new StringBuffer(60);
1147 String dateStr = Integer.toString(DateFromTime(date));
1148 String hourStr = Integer.toString(HourFromTime(date));
1149 String minStr = Integer.toString(MinFromTime(date));
1150 String secStr = Integer.toString(SecFromTime(date));
1151 int year = YearFromTime(date);
1152 String yearStr = Integer.toString(year > 0 ? year : -year);
1154 result.append(days[WeekDay(date)]);
1155 result.append(", ");
1156 if (dateStr.length() == 1)
1158 result.append(dateStr);
1160 result.append(months[MonthFromTime(date)]);
1162 result.append(" -");
1166 for (i = yearStr.length(); i < 4; i++)
1168 result.append(yearStr);
1170 if (hourStr.length() == 1)
1171 result.append(" 0");
1174 result.append(hourStr);
1175 if (minStr.length() == 1)
1176 result.append(":0");
1179 result.append(minStr);
1180 if (secStr.length() == 1)
1181 result.append(":0");
1184 result.append(secStr);
1186 result.append(" GMT");
1187 return result.toString();
1190 private static double jsFunction_getYear(double date) {
1191 int result = YearFromTime(LocalTime(date));
1196 private static double jsFunction_getTimezoneOffset(double date) {
1197 return (date - LocalTime(date)) / msPerMinute;
1200 public double jsFunction_setTime(double time) {
1201 this.date = TimeClip(time);
1205 private double makeTime(Object[] args, int maxargs, boolean local) {
1207 double conv[] = new double[4];
1208 double hour, min, sec, msec;
1209 double lorutime; /* Local or UTC version of date */
1214 double date = this.date;
1216 /* just return NaN if the date is already NaN */
1220 /* Satisfy the ECMA rule that if a function is called with
1221 * fewer arguments than the specified formal arguments, the
1222 * remaining arguments are set to undefined. Seems like all
1223 * the Date.setWhatever functions in ECMA are only varargs
1224 * beyond the first argument; this should be set to undefined
1225 * if it's not given. This means that "d = new Date();
1226 * d.setMilliseconds()" returns NaN. Blech.
1228 if (args.length == 0)
1229 args = new Object[] { null };
1231 for (i = 0; i < args.length && i < maxargs; i++) {
1232 conv[i] = _toNumber(args[i]);
1234 // limit checks that happen in MakeTime in ECMA.
1235 if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1236 this.date = Double.NaN;
1239 conv[i] = toDouble(conv[i]);
1243 lorutime = LocalTime(date);
1248 int stop = args.length;
1250 if (maxargs >= 4 && i < stop)
1253 hour = HourFromTime(lorutime);
1255 if (maxargs >= 3 && i < stop)
1258 min = MinFromTime(lorutime);
1260 if (maxargs >= 2 && i < stop)
1263 sec = SecFromTime(lorutime);
1265 if (maxargs >= 1 && i < stop)
1268 msec = msFromTime(lorutime);
1270 time = MakeTime(hour, min, sec, msec);
1271 result = MakeDate(Day(lorutime), time);
1274 result = internalUTC(result);
1275 date = TimeClip(result);
1281 private double jsFunction_setHours(Object[] args) {
1282 return makeTime(args, 4, true);
1285 private double jsFunction_setUTCHours(Object[] args) {
1286 return makeTime(args, 4, false);
1289 private double makeDate(Object[] args, int maxargs, boolean local) {
1291 double conv[] = new double[3];
1292 double year, month, day;
1293 double lorutime; /* local or UTC version of date */
1296 double date = this.date;
1298 /* See arg padding comment in makeTime.*/
1299 if (args.length == 0)
1300 args = new Object[] { null };
1302 for (i = 0; i < args.length && i < maxargs; i++) {
1303 conv[i] = _toNumber(args[i]);
1305 // limit checks that happen in MakeDate in ECMA.
1306 if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1307 this.date = Double.NaN;
1310 conv[i] = toDouble(conv[i]);
1313 /* return NaN if date is NaN and we're not setting the year,
1314 * If we are, use 0 as the time. */
1316 if (args.length < 3) {
1323 lorutime = LocalTime(date);
1329 int stop = args.length;
1331 if (maxargs >= 3 && i < stop)
1334 year = YearFromTime(lorutime);
1336 if (maxargs >= 2 && i < stop)
1339 month = MonthFromTime(lorutime);
1341 if (maxargs >= 1 && i < stop)
1344 day = DateFromTime(lorutime);
1346 day = MakeDay(year, month, day); /* day within year */
1347 result = MakeDate(day, TimeWithinDay(lorutime));
1350 result = internalUTC(result);
1352 date = TimeClip(result);
1358 private double jsFunction_setYear(double year) {
1360 if (year != year || Double.isInfinite(year)) {
1361 this.date = Double.NaN;
1365 if (this.date != this.date) {
1368 this.date = LocalTime(this.date);
1371 if (year >= 0 && year <= 99)
1374 day = MakeDay(year, MonthFromTime(this.date), DateFromTime(this.date));
1375 result = MakeDate(day, TimeWithinDay(this.date));
1376 result = internalUTC(result);
1378 this.date = TimeClip(result);
1382 protected String getIdName(int id) {
1384 case ConstructorId_UTC: return "UTC";
1385 case ConstructorId_parse: return "parse";
1386 case Id_constructor: return "constructor";
1387 case Id_toString: return "toString";
1388 case Id_toTimeString: return "toTimeString";
1389 case Id_toDateString: return "toDateString";
1390 case Id_toLocaleString: return "toLocaleString";
1391 case Id_toLocaleTimeString: return "toLocaleTimeString";
1392 case Id_toLocaleDateString: return "toLocaleDateString";
1393 case Id_toUTCString: return "toUTCString";
1394 case Id_valueOf: return "valueOf";
1395 case Id_getTime: return "getTime";
1396 case Id_getYear: return "getYear";
1397 case Id_getFullYear: return "getFullYear";
1398 case Id_getUTCFullYear: return "getUTCFullYear";
1399 case Id_getMonth: return "getMonth";
1400 case Id_getUTCMonth: return "getUTCMonth";
1401 case Id_getDate: return "getDate";
1402 case Id_getUTCDate: return "getUTCDate";
1403 case Id_getDay: return "getDay";
1404 case Id_getUTCDay: return "getUTCDay";
1405 case Id_getHours: return "getHours";
1406 case Id_getUTCHours: return "getUTCHours";
1407 case Id_getMinutes: return "getMinutes";
1408 case Id_getUTCMinutes: return "getUTCMinutes";
1409 case Id_getSeconds: return "getSeconds";
1410 case Id_getUTCSeconds: return "getUTCSeconds";
1411 case Id_getMilliseconds: return "getMilliseconds";
1412 case Id_getUTCMilliseconds: return "getUTCMilliseconds";
1413 case Id_getTimezoneOffset: return "getTimezoneOffset";
1414 case Id_setTime: return "setTime";
1415 case Id_setMilliseconds: return "setMilliseconds";
1416 case Id_setUTCMilliseconds: return "setUTCMilliseconds";
1417 case Id_setSeconds: return "setSeconds";
1418 case Id_setUTCSeconds: return "setUTCSeconds";
1419 case Id_setMinutes: return "setMinutes";
1420 case Id_setUTCMinutes: return "setUTCMinutes";
1421 case Id_setHours: return "setHours";
1422 case Id_setUTCHours: return "setUTCHours";
1423 case Id_setDate: return "setDate";
1424 case Id_setUTCDate: return "setUTCDate";
1425 case Id_setMonth: return "setMonth";
1426 case Id_setUTCMonth: return "setUTCMonth";
1427 case Id_setFullYear: return "setFullYear";
1428 case Id_setUTCFullYear: return "setUTCFullYear";
1429 case Id_setYear: return "setYear";
1436 protected int mapNameToId(String s) {
1438 // #generated# Last update: 2001-04-22 23:46:59 CEST
1439 L0: { id = 0; String X = null; int c;
1440 L: switch (s.length()) {
1441 case 6: X="getDay";id=Id_getDay; break L;
1442 case 7: switch (s.charAt(3)) {
1443 case 'D': c=s.charAt(0);
1444 if (c=='g') { X="getDate";id=Id_getDate; }
1445 else if (c=='s') { X="setDate";id=Id_setDate; }
1447 case 'T': c=s.charAt(0);
1448 if (c=='g') { X="getTime";id=Id_getTime; }
1449 else if (c=='s') { X="setTime";id=Id_setTime; }
1451 case 'Y': c=s.charAt(0);
1452 if (c=='g') { X="getYear";id=Id_getYear; }
1453 else if (c=='s') { X="setYear";id=Id_setYear; }
1455 case 'u': X="valueOf";id=Id_valueOf; break L;
1457 case 8: c=s.charAt(0);
1460 if (c=='h') { X="getMonth";id=Id_getMonth; }
1461 else if (c=='s') { X="getHours";id=Id_getHours; }
1465 if (c=='h') { X="setMonth";id=Id_setMonth; }
1466 else if (c=='s') { X="setHours";id=Id_setHours; }
1468 else if (c=='t') { X="toString";id=Id_toString; }
1470 case 9: X="getUTCDay";id=Id_getUTCDay; break L;
1471 case 10: c=s.charAt(3);
1474 if (c=='g') { X="getMinutes";id=Id_getMinutes; }
1475 else if (c=='s') { X="setMinutes";id=Id_setMinutes; }
1479 if (c=='g') { X="getSeconds";id=Id_getSeconds; }
1480 else if (c=='s') { X="setSeconds";id=Id_setSeconds; }
1484 if (c=='g') { X="getUTCDate";id=Id_getUTCDate; }
1485 else if (c=='s') { X="setUTCDate";id=Id_setUTCDate; }
1488 case 11: switch (s.charAt(3)) {
1489 case 'F': c=s.charAt(0);
1490 if (c=='g') { X="getFullYear";id=Id_getFullYear; }
1491 else if (c=='s') { X="setFullYear";id=Id_setFullYear; }
1493 case 'M': X="toGMTString";id=Id_toGMTString; break L;
1494 case 'T': X="toUTCString";id=Id_toUTCString; break L;
1495 case 'U': c=s.charAt(0);
1498 if (c=='r') { X="getUTCHours";id=Id_getUTCHours; }
1499 else if (c=='t') { X="getUTCMonth";id=Id_getUTCMonth; }
1503 if (c=='r') { X="setUTCHours";id=Id_setUTCHours; }
1504 else if (c=='t') { X="setUTCMonth";id=Id_setUTCMonth; }
1507 case 's': X="constructor";id=Id_constructor; break L;
1509 case 12: c=s.charAt(2);
1510 if (c=='D') { X="toDateString";id=Id_toDateString; }
1511 else if (c=='T') { X="toTimeString";id=Id_toTimeString; }
1513 case 13: c=s.charAt(0);
1516 if (c=='M') { X="getUTCMinutes";id=Id_getUTCMinutes; }
1517 else if (c=='S') { X="getUTCSeconds";id=Id_getUTCSeconds; }
1521 if (c=='M') { X="setUTCMinutes";id=Id_setUTCMinutes; }
1522 else if (c=='S') { X="setUTCSeconds";id=Id_setUTCSeconds; }
1525 case 14: c=s.charAt(0);
1526 if (c=='g') { X="getUTCFullYear";id=Id_getUTCFullYear; }
1527 else if (c=='s') { X="setUTCFullYear";id=Id_setUTCFullYear; }
1528 else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; }
1530 case 15: c=s.charAt(0);
1531 if (c=='g') { X="getMilliseconds";id=Id_getMilliseconds; }
1532 else if (c=='s') { X="setMilliseconds";id=Id_setMilliseconds; }
1534 case 17: X="getTimezoneOffset";id=Id_getTimezoneOffset; break L;
1535 case 18: c=s.charAt(0);
1536 if (c=='g') { X="getUTCMilliseconds";id=Id_getUTCMilliseconds; }
1537 else if (c=='s') { X="setUTCMilliseconds";id=Id_setUTCMilliseconds; }
1540 if (c=='D') { X="toLocaleDateString";id=Id_toLocaleDateString; }
1541 else if (c=='T') { X="toLocaleTimeString";id=Id_toLocaleTimeString; }
1545 if (X!=null && X!=s && !X.equals(s)) id = 0;
1551 private static final int
1552 ConstructorId_UTC = -2,
1553 ConstructorId_parse = -1,
1557 Id_toTimeString = 3,
1558 Id_toDateString = 4,
1559 Id_toLocaleString = 5,
1560 Id_toLocaleTimeString = 6,
1561 Id_toLocaleDateString = 7,
1566 Id_getFullYear = 12,
1567 Id_getUTCFullYear = 13,
1569 Id_getUTCMonth = 15,
1575 Id_getUTCHours = 21,
1577 Id_getUTCMinutes = 23,
1579 Id_getUTCSeconds = 25,
1580 Id_getMilliseconds = 26,
1581 Id_getUTCMilliseconds = 27,
1582 Id_getTimezoneOffset = 28,
1584 Id_setMilliseconds = 30,
1585 Id_setUTCMilliseconds = 31,
1587 Id_setUTCSeconds = 33,
1589 Id_setUTCMinutes = 35,
1591 Id_setUTCHours = 37,
1595 Id_setUTCMonth = 41,
1596 Id_setFullYear = 42,
1597 Id_setUTCFullYear = 43,
1600 MAX_PROTOTYPE_ID = 44;
1602 private static final int
1603 Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6
1607 private static java.util.TimeZone thisTimeZone;
1608 private static double LocalTZA;
1609 private static java.text.DateFormat timeZoneFormatter;
1610 private static java.text.DateFormat localeDateTimeFormatter;
1611 private static java.text.DateFormat localeDateFormatter;
1612 private static java.text.DateFormat localeTimeFormatter;
1614 private double date;
1616 public long getRawTime() { return (long)this.date; }