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.text.DateFormat;
42 * This class implements the Date native object.
45 * @author Adam Megacz (many modifications
47 public class JSDate extends JS {
50 if (thisTimeZone == null) {
51 // j.u.TimeZone is synchronized, so setting class statics from it
53 thisTimeZone = java.util.TimeZone.getDefault();
54 LocalTZA = thisTimeZone.getRawOffset();
58 String coerceToString() { return date_format(date, FORMATSPEC_FULL); }
60 public JS callMethod(JS method_, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
61 if(!JS.isString(method_)) return super.callMethod(method_, a0, a1, a2, rest, nargs);
62 String method = JS.toString(method_);
66 case "toString": return JS.S(date_format(date, FORMATSPEC_FULL));
67 case "toTimeString": return JS.S(date_format(date, FORMATSPEC_TIME));
68 case "toDateString": return JS.S(date_format(date, FORMATSPEC_DATE));
69 case "toLocaleString": return JS.S(toLocaleString(date));
70 case "toLocaleTimeString": return JS.S(toLocaleTimeString(date));
71 case "toLocaleDateString": return JS.S(toLocaleDateString(date));
72 case "toUTCString": return JS.S(toUTCString(date));
73 case "valueOf": return N(this.date);
74 case "getTime": return N(this.date);
75 case "getYear": return N(getYear(date));
76 case "getFullYear": return N(YearFromTime(LocalTime(date)));
77 case "getUTCFullYear": return N(YearFromTime(date));
78 case "getMonth": return N(MonthFromTime(LocalTime(date)));
79 case "getUTCMonth": return N(MonthFromTime(date));
80 case "getDate": return N(DateFromTime(LocalTime(date)));
81 case "getUTCDate": return N(DateFromTime(date));
82 case "getDay": return N(WeekDay(LocalTime(date)));
83 case "getUTCDay": return N(WeekDay(date));
84 case "getHours": return N(HourFromTime(LocalTime(date)));
85 case "getUTCHours": return N(HourFromTime(date));
86 case "getMinutes": return N(MinFromTime(LocalTime(date)));
87 case "getUTCMinutes": return N(MinFromTime(date));
88 case "getSeconds": return N(SecFromTime(LocalTime(date)));
89 case "getUTCSeconds": return N(SecFromTime(date));
90 case "getMilliseconds": return N(msFromTime(LocalTime(date)));
91 case "getUTCMilliseconds": return N(msFromTime(date));
92 case "getTimezoneOffset": return N(getTimezoneOffset(date));
94 return super.callMethod(method_, a0, a1, a2, rest, nargs);
98 case "setTime": return N(this.setTime(toDouble(a0)));
99 case "setYear": return N(this.setYear(toDouble(a0)));
104 JS[] args = new JS[nargs];
105 for(int i=0; i<nargs; i++) args[i] = i==0 ? a0 : i==1 ? a1 : i==2 ? a2 : rest[i-3];
107 case "setMilliseconds": return N(this.makeTime(args, 1, true));
108 case "setUTCMilliseconds": return N(this.makeTime(args, 1, false));
109 case "setSeconds": return N(this.makeTime(args, 2, true));
110 case "setUTCSeconds": return N(this.makeTime(args, 2, false));
111 case "setMinutes": return N(this.makeTime(args, 3, true));
112 case "setUTCMinutes": return N(this.makeTime(args, 3, false));
113 case "setHours": return N(this.makeTime(args, 4, true));
114 case "setUTCHours": return N(this.makeTime(args, 4, false));
115 case "setDate": return N(this.makeDate(args, 1, true));
116 case "setUTCDate": return N(this.makeDate(args, 1, false));
117 case "setMonth": return N(this.makeDate(args, 2, true));
118 case "setUTCMonth": return N(this.makeDate(args, 2, false));
119 case "setFullYear": return N(this.makeDate(args, 3, true));
120 case "setUTCFullYear": return N(this.makeDate(args, 3, false));
124 return super.callMethod(method_, a0, a1, a2, rest, nargs);
127 public JS get(JS key_) throws JSExn {
128 if(!JS.isString(key_)) return super.get(key_);
129 String key = JS.toString(key_);
131 case "toString": return METHOD;
132 case "toTimeString": return METHOD;
133 case "toDateString": return METHOD;
134 case "toLocaleString": return METHOD;
135 case "toLocaleTimeString": return METHOD;
136 case "toLocaleDateString": return METHOD;
137 case "toUTCString": return METHOD;
138 case "valueOf": return METHOD;
139 case "getTime": return METHOD;
140 case "getYear": return METHOD;
141 case "getFullYear": return METHOD;
142 case "getUTCFullYear": return METHOD;
143 case "getMonth": return METHOD;
144 case "getUTCMonth": return METHOD;
145 case "getDate": return METHOD;
146 case "getUTCDate": return METHOD;
147 case "getDay": return METHOD;
148 case "getUTCDay": return METHOD;
149 case "getHours": return METHOD;
150 case "getUTCHours": return METHOD;
151 case "getMinutes": return METHOD;
152 case "getUTCMinutes": return METHOD;
153 case "getSeconds": return METHOD;
154 case "getUTCSeconds": return METHOD;
155 case "getMilliseconds": return METHOD;
156 case "getUTCMilliseconds": return METHOD;
157 case "getTimezoneOffset": return METHOD;
158 case "setTime": return METHOD;
159 case "setYear": return METHOD;
160 case "setMilliseconds": return METHOD;
161 case "setUTCMilliseconds": return METHOD;
162 case "setSeconds": return METHOD;
163 case "setUTCSeconds": return METHOD;
164 case "setMinutes": return METHOD;
165 case "setUTCMinutes": return METHOD;
166 case "setHours": return METHOD;
167 case "setUTCHours": return METHOD;
168 case "setDate": return METHOD;
169 case "setUTCDate": return METHOD;
170 case "setMonth": return METHOD;
171 case "setUTCMonth": return METHOD;
172 case "setFullYear": return METHOD;
173 case "setUTCFullYear": return METHOD;
175 return super.get(key_);
178 /* ECMA helper functions */
180 private static final double HalfTimeDomain = 8.64e15;
181 private static final double HoursPerDay = 24.0;
182 private static final double MinutesPerHour = 60.0;
183 private static final double SecondsPerMinute = 60.0;
184 private static final double msPerSecond = 1000.0;
185 private static final double MinutesPerDay = (HoursPerDay * MinutesPerHour);
186 private static final double SecondsPerDay = (MinutesPerDay * SecondsPerMinute);
187 private static final double SecondsPerHour = (MinutesPerHour * SecondsPerMinute);
188 private static final double msPerDay = (SecondsPerDay * msPerSecond);
189 private static final double msPerHour = (SecondsPerHour * msPerSecond);
190 private static final double msPerMinute = (SecondsPerMinute * msPerSecond);
192 private static double Day(double t) {
193 return java.lang.Math.floor(t / msPerDay);
196 private static double TimeWithinDay(double t) {
198 result = t % msPerDay;
204 private static int DaysInYear(int y) {
205 if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
212 /* math here has to be f.p, because we need
213 * floor((1968 - 1969) / 4) == -1
215 private static double DayFromYear(double y) {
216 return ((365 * ((y)-1970) + java.lang.Math.floor(((y)-1969)/4.0)
217 - java.lang.Math.floor(((y)-1901)/100.0) + java.lang.Math.floor(((y)-1601)/400.0)));
220 private static double TimeFromYear(double y) {
221 return DayFromYear(y) * msPerDay;
224 private static int YearFromTime(double t) {
225 int lo = (int) java.lang.Math.floor((t / msPerDay) / 366) + 1970;
226 int hi = (int) java.lang.Math.floor((t / msPerDay) / 365) + 1970;
229 /* above doesn't work for negative dates... */
236 /* Use a simple binary search algorithm to find the right
237 year. This seems like brute force... but the computation
238 of hi and lo years above lands within one year of the
239 correct answer for years within a thousand years of
240 1970; the loop below only requires six iterations
244 if (TimeFromYear(mid) > t) {
247 if (TimeFromYear(mid) <= t) {
249 if (TimeFromYear(temp) > t) {
259 private static boolean InLeapYear(double t) {
260 return DaysInYear(YearFromTime(t)) == 366;
263 private static int DayWithinYear(double t) {
264 int year = YearFromTime(t);
265 return (int) (Day(t) - DayFromYear(year));
268 * The following array contains the day of year for the first day of
269 * each month, where index 0 is January, and day 0 is January 1.
272 private static double DayFromMonth(int m, boolean leap) {
275 if (m >= 7) { day += m / 2 - 1; }
276 else if (m >= 2) { day += (m - 1) / 2 - 1; }
279 if (leap && m >= 2) { ++day; }
284 private static int MonthFromTime(double t) {
287 d = DayWithinYear(t);
292 // Originally coded as step += (InLeapYear(t) ? 29 : 28);
293 // but some jits always returned 28!
301 if (d < (step += 31))
303 if (d < (step += 30))
305 if (d < (step += 31))
307 if (d < (step += 30))
309 if (d < (step += 31))
311 if (d < (step += 31))
313 if (d < (step += 30))
315 if (d < (step += 31))
317 if (d < (step += 30))
322 private static int DateFromTime(double t) {
325 d = DayWithinYear(t);
326 if (d <= (next = 30))
330 // Originally coded as next += (InLeapYear(t) ? 29 : 28);
331 // but some jits always returned 28!
340 if (d <= (next += 31))
343 if (d <= (next += 30))
346 if (d <= (next += 31))
349 if (d <= (next += 30))
352 if (d <= (next += 31))
355 if (d <= (next += 31))
358 if (d <= (next += 30))
361 if (d <= (next += 31))
364 if (d <= (next += 30))
371 private static int WeekDay(double t) {
380 private static double Now() {
381 return (double) System.currentTimeMillis();
384 /* Should be possible to determine the need for this dynamically
385 * if we go with the workaround... I'm not using it now, because I
386 * can't think of any clean way to make toLocaleString() and the
387 * time zone (comment) in toString match the generated string
388 * values. Currently it's wrong-but-consistent in all but the
389 * most recent betas of the JRE - seems to work in 1.1.7.
391 private final static boolean TZO_WORKAROUND = false;
392 private static double DaylightSavingTA(double t) {
393 if (!TZO_WORKAROUND) {
394 java.util.Date date = new java.util.Date((long) t);
395 if (thisTimeZone.inDaylightTime(date))
400 /* Use getOffset if inDaylightTime() is broken, because it
401 * seems to work acceptably. We don't switch over to it
402 * entirely, because it requires (expensive) exploded date arguments,
403 * and the api makes it impossible to handle dst
404 * changeovers cleanly.
407 // Hardcode the assumption that the changeover always
408 // happens at 2:00 AM:
409 t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);
411 int year = YearFromTime(t);
412 double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0,
417 (int)TimeWithinDay(t));
419 if ((offset - LocalTZA) != 0)
423 // return offset - LocalTZA;
427 private static double LocalTime(double t) {
428 return t + LocalTZA + DaylightSavingTA(t);
431 public static double internalUTC(double t) {
432 return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
435 private static int HourFromTime(double t) {
437 result = java.lang.Math.floor(t / msPerHour) % HoursPerDay;
439 result += HoursPerDay;
443 private static int MinFromTime(double t) {
445 result = java.lang.Math.floor(t / msPerMinute) % MinutesPerHour;
447 result += MinutesPerHour;
451 private static int SecFromTime(double t) {
453 result = java.lang.Math.floor(t / msPerSecond) % SecondsPerMinute;
455 result += SecondsPerMinute;
459 private static int msFromTime(double t) {
461 result = t % msPerSecond;
463 result += msPerSecond;
467 private static double MakeTime(double hour, double min,
468 double sec, double ms)
470 return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)
474 private static double MakeDay(double year, double month, double date) {
480 year += java.lang.Math.floor(month / 12);
486 leap = (DaysInYear((int) year) == 366);
488 yearday = java.lang.Math.floor(TimeFromYear(year) / msPerDay);
489 monthday = DayFromMonth((int) month, leap);
497 private static double MakeDate(double day, double time) {
498 return day * msPerDay + time;
501 private static double TimeClip(double d) {
503 d == Double.POSITIVE_INFINITY ||
504 d == Double.NEGATIVE_INFINITY ||
505 java.lang.Math.abs(d) > HalfTimeDomain)
510 return java.lang.Math.floor(d + 0.);
512 return java.lang.Math.ceil(d + 0.);
515 /* end of ECMA helper functions */
517 /* find UTC time from given date... no 1900 correction! */
518 public static double date_msecFromDate(double year, double mon,
519 double mday, double hour,
520 double min, double sec,
527 day = MakeDay(year, mon, mday);
528 time = MakeTime(hour, min, sec, msec);
529 result = MakeDate(day, time);
534 private static final int MAXARGS = 7;
535 private static double jsStaticJSFunction_UTC(JS[] args) throws JSExn {
536 double array[] = new double[MAXARGS];
540 for (loop = 0; loop < MAXARGS; loop++) {
541 if (loop < args.length) {
542 d = _toNumber(args[loop]);
543 if (d != d || Double.isInfinite(d)) {
546 array[loop] = toDouble(args[loop]);
552 /* adjust 2-digit years into the 20th century */
553 if (array[0] >= 0 && array[0] <= 99)
556 /* if we got a 0 for 'date' (which is out of range)
557 * pretend it's a 1. (So Date.UTC(1972, 5) works) */
561 d = date_msecFromDate(array[0], array[1], array[2],
562 array[3], array[4], array[5], array[6]);
569 * Use ported code from jsdate.c rather than the locale-specific
570 * date-parsing code from Java, to keep js and rhino consistent.
571 * Is this the right strategy?
574 /* for use by date_parse */
576 /* replace this with byte arrays? Cheaper? */
577 private static String wtb[] = {
579 "monday", "tuesday", "wednesday", "thursday", "friday",
580 "saturday", "sunday",
581 "january", "february", "march", "april", "may", "june",
582 "july", "august", "september", "october", "november", "december",
583 "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
584 "mst", "mdt", "pst", "pdt"
585 /* time zone table needs to be expanded */
588 private static int ttb[] = {
589 -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
590 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
591 10000 + 0, 10000 + 0, 10000 + 0, /* UT/UTC */
592 10000 + 5 * 60, 10000 + 4 * 60, /* EDT */
593 10000 + 6 * 60, 10000 + 5 * 60,
594 10000 + 7 * 60, 10000 + 6 * 60,
595 10000 + 8 * 60, 10000 + 7 * 60
598 /* helper for date_parse */
599 private static boolean date_regionMatches(String s1, int s1off,
600 String s2, int s2off,
603 boolean result = false;
604 /* return true if matches, otherwise, false */
605 int s1len = s1.length();
606 int s2len = s2.length();
608 while (count > 0 && s1off < s1len && s2off < s2len) {
609 if (Character.toLowerCase(s1.charAt(s1off)) !=
610 Character.toLowerCase(s2.charAt(s2off)))
623 private static double date_parseString(String s) {
636 double tzoffset = -1;
639 boolean seenplusminus = false;
641 if (s == null) // ??? Will s be null?
647 if (c <= ' ' || c == ',' || c == '-') {
650 if (c == '-' && '0' <= si && si <= '9') {
656 if (c == '(') { /* comments) */
669 if ('0' <= c && c <= '9') {
671 while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
672 n = n * 10 + c - '0';
676 /* allow TZA before the year, so
677 * 'Wed Nov 05 21:49:11 GMT-0800 1997'
680 /* uses of seenplusminus allow : in TZA, so Java
681 * no-timezone style of GMT+4:30 works
683 if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
684 /* make ':' case below change tzoffset */
685 seenplusminus = true;
689 n = n * 60; /* EG. "GMT-3" */
691 n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
692 if (prevc == '+') /* plus means east of GMT */
694 if (tzoffset != 0 && tzoffset != -1)
697 } else if (n >= 70 ||
698 (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
701 else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
702 year = n < 100 ? n + 1900 : n;
705 } else if (c == ':') {
712 } else if (c == '/') {
719 } else if (i < limit && c != ',' && c > ' ' && c != '-') {
721 } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
726 } else if (hour >= 0 && min < 0) {
728 } else if (min >= 0 && sec < 0) {
730 } else if (mday < 0) {
736 } else if (c == '/' || c == ':' || c == '+' || c == '-') {
743 if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
749 for (k = wtb.length; --k >= 0;)
750 if (date_regionMatches(wtb[k], 0, s, st, i-st)) {
755 * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
756 * 12:30, instead of blindly adding 12 if PM.
758 if (hour > 12 || hour < 0) {
761 if (action == -1 && hour == 12) { // am
763 } else if (action == -2 && hour != 12) {// pm
767 } else if (action <= 13) { /* month! */
769 mon = /*byte*/ (action - 2);
774 tzoffset = action - 10000;
784 if (year < 0 || mon < 0 || mday < 0)
792 if (tzoffset == -1) { /* no time zone specified, have to use local */
794 time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
795 return internalUTC(time);
798 msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
799 msec += tzoffset * msPerMinute;
803 private static double jsStaticJSFunction_parse(String s) {
804 return date_parseString(s);
807 private static final int FORMATSPEC_FULL = 0;
808 private static final int FORMATSPEC_DATE = 1;
809 private static final int FORMATSPEC_TIME = 2;
811 private static String date_format(double t, int format) {
815 StringBuffer result = new StringBuffer(60);
816 double local = LocalTime(t);
818 /* offset from GMT in minutes. The offset includes daylight savings,
820 int minutes = (int) java.lang.Math.floor((LocalTZA + DaylightSavingTA(t))
822 /* map 510 minutes to 0830 hours */
823 int offset = (minutes / 60) * 100 + minutes % 60;
825 String dateStr = Integer.toString(DateFromTime(local));
826 String hourStr = Integer.toString(HourFromTime(local));
827 String minStr = Integer.toString(MinFromTime(local));
828 String secStr = Integer.toString(SecFromTime(local));
829 String offsetStr = Integer.toString(offset > 0 ? offset : -offset);
830 int year = YearFromTime(local);
831 String yearStr = Integer.toString(year > 0 ? year : -year);
833 /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
834 /* Tue Oct 31 2000 */
835 /* 09:41:40 GMT-0800 (PST) */
837 if (format != FORMATSPEC_TIME) {
838 result.append(days[WeekDay(local)]);
840 result.append(months[MonthFromTime(local)]);
841 if (dateStr.length() == 1)
845 result.append(dateStr);
849 if (format != FORMATSPEC_DATE) {
850 if (hourStr.length() == 1)
852 result.append(hourStr);
853 if (minStr.length() == 1)
857 result.append(minStr);
858 if (secStr.length() == 1)
862 result.append(secStr);
864 result.append(" GMT+");
866 result.append(" GMT-");
867 for (int i = offsetStr.length(); i < 4; i++)
869 result.append(offsetStr);
871 if (timeZoneFormatter == null)
872 timeZoneFormatter = new java.text.SimpleDateFormat("zzz");
874 if (timeZoneFormatter != null) {
876 java.util.Date date = new java.util.Date((long) t);
877 result.append(timeZoneFormatter.format(date));
880 if (format != FORMATSPEC_TIME)
884 if (format != FORMATSPEC_TIME) {
887 for (int i = yearStr.length(); i < 4; i++)
889 result.append(yearStr);
892 return result.toString();
895 private static double _toNumber(JS o) throws JSExn { return JS.toDouble(o); }
896 private static double _toNumber(JS[] o, int index) throws JSExn { return JS.toDouble(o[index]); }
897 private static double toDouble(double d) { return d; }
899 public JSDate(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
910 date = date_parseString(JS.toString(a0));
912 date = _toNumber(a0);
913 obj.date = TimeClip(date);
917 // multiple arguments; year, month, day etc.
918 double array[] = new double[MAXARGS];
919 array[0] = toDouble(a0);
920 array[1] = toDouble(a1);
921 if (nargs >= 2) array[2] = toDouble(a2);
922 for(int i=0; i<nargs; i++) {
923 double d = _toNumber(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
924 if (d != d || Double.isInfinite(d)) {
925 obj.date = Double.NaN;
931 /* adjust 2-digit years into the 20th century */
932 if (array[0] >= 0 && array[0] <= 99)
935 /* if we got a 0 for 'date' (which is out of range)
936 * pretend it's a 1 */
940 double day = MakeDay(array[0], array[1], array[2]);
941 double time = MakeTime(array[3], array[4], array[5], array[6]);
942 time = MakeDate(day, time);
943 time = internalUTC(time);
944 obj.date = TimeClip(time);
951 /* constants for toString, toUTCString */
952 private static String NaN_date_str = "Invalid Date";
954 private static String[] days = {
955 "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
958 private static String[] months = {
959 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
960 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
963 private static String toLocale_helper(double t,
964 java.text.DateFormat formatter)
969 java.util.Date tempdate = new java.util.Date((long) t);
970 return formatter.format(tempdate);
973 private static String toLocaleString(double date) {
974 if (localeDateTimeFormatter == null)
975 localeDateTimeFormatter =
976 DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
978 return toLocale_helper(date, localeDateTimeFormatter);
981 private static String toLocaleTimeString(double date) {
982 if (localeTimeFormatter == null)
983 localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG);
985 return toLocale_helper(date, localeTimeFormatter);
988 private static String toLocaleDateString(double date) {
989 if (localeDateFormatter == null)
990 localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG);
992 return toLocale_helper(date, localeDateFormatter);
995 private static String toUTCString(double date) {
996 StringBuffer result = new StringBuffer(60);
998 String dateStr = Integer.toString(DateFromTime(date));
999 String hourStr = Integer.toString(HourFromTime(date));
1000 String minStr = Integer.toString(MinFromTime(date));
1001 String secStr = Integer.toString(SecFromTime(date));
1002 int year = YearFromTime(date);
1003 String yearStr = Integer.toString(year > 0 ? year : -year);
1005 result.append(days[WeekDay(date)]);
1006 result.append(", ");
1007 if (dateStr.length() == 1)
1009 result.append(dateStr);
1011 result.append(months[MonthFromTime(date)]);
1013 result.append(" -");
1017 for (i = yearStr.length(); i < 4; i++)
1019 result.append(yearStr);
1021 if (hourStr.length() == 1)
1022 result.append(" 0");
1025 result.append(hourStr);
1026 if (minStr.length() == 1)
1027 result.append(":0");
1030 result.append(minStr);
1031 if (secStr.length() == 1)
1032 result.append(":0");
1035 result.append(secStr);
1037 result.append(" GMT");
1038 return result.toString();
1041 private static double getYear(double date) {
1042 int result = YearFromTime(LocalTime(date));
1047 private static double getTimezoneOffset(double date) {
1048 return (date - LocalTime(date)) / msPerMinute;
1051 public double setTime(double time) {
1052 this.date = TimeClip(time);
1056 private double makeTime(JS[] args, int maxargs, boolean local) throws JSExn {
1058 double conv[] = new double[4];
1059 double hour, min, sec, msec;
1060 double lorutime; /* Local or UTC version of date */
1065 double date = this.date;
1067 /* just return NaN if the date is already NaN */
1071 /* Satisfy the ECMA rule that if a function is called with
1072 * fewer arguments than the specified formal arguments, the
1073 * remaining arguments are set to undefined. Seems like all
1074 * the Date.setWhatever functions in ECMA are only varargs
1075 * beyond the first argument; this should be set to undefined
1076 * if it's not given. This means that "d = new Date();
1077 * d.setMilliseconds()" returns NaN. Blech.
1079 if (args.length == 0)
1080 args = new JS[] { null };
1082 for (i = 0; i < args.length && i < maxargs; i++) {
1083 conv[i] = _toNumber(args[i]);
1085 // limit checks that happen in MakeTime in ECMA.
1086 if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1087 this.date = Double.NaN;
1090 conv[i] = toDouble(conv[i]);
1094 lorutime = LocalTime(date);
1099 int stop = args.length;
1101 if (maxargs >= 4 && i < stop)
1104 hour = HourFromTime(lorutime);
1106 if (maxargs >= 3 && i < stop)
1109 min = MinFromTime(lorutime);
1111 if (maxargs >= 2 && i < stop)
1114 sec = SecFromTime(lorutime);
1116 if (maxargs >= 1 && i < stop)
1119 msec = msFromTime(lorutime);
1121 time = MakeTime(hour, min, sec, msec);
1122 result = MakeDate(Day(lorutime), time);
1125 result = internalUTC(result);
1126 date = TimeClip(result);
1132 private double setHours(JS[] args) throws JSExn {
1133 return makeTime(args, 4, true);
1136 private double setUTCHours(JS[] args) throws JSExn {
1137 return makeTime(args, 4, false);
1140 private double makeDate(JS[] args, int maxargs, boolean local) throws JSExn {
1142 double conv[] = new double[3];
1143 double year, month, day;
1144 double lorutime; /* local or UTC version of date */
1147 double date = this.date;
1149 /* See arg padding comment in makeTime.*/
1150 if (args.length == 0)
1151 args = new JS[] { null };
1153 for (i = 0; i < args.length && i < maxargs; i++) {
1154 conv[i] = _toNumber(args[i]);
1156 // limit checks that happen in MakeDate in ECMA.
1157 if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1158 this.date = Double.NaN;
1161 conv[i] = toDouble(conv[i]);
1164 /* return NaN if date is NaN and we're not setting the year,
1165 * If we are, use 0 as the time. */
1167 if (args.length < 3) {
1174 lorutime = LocalTime(date);
1180 int stop = args.length;
1182 if (maxargs >= 3 && i < stop)
1185 year = YearFromTime(lorutime);
1187 if (maxargs >= 2 && i < stop)
1190 month = MonthFromTime(lorutime);
1192 if (maxargs >= 1 && i < stop)
1195 day = DateFromTime(lorutime);
1197 day = MakeDay(year, month, day); /* day within year */
1198 result = MakeDate(day, TimeWithinDay(lorutime));
1201 result = internalUTC(result);
1203 date = TimeClip(result);
1209 private double setYear(double year) {
1211 if (year != year || Double.isInfinite(year)) {
1212 this.date = Double.NaN;
1216 if (this.date != this.date) {
1219 this.date = LocalTime(this.date);
1222 if (year >= 0 && year <= 99)
1225 day = MakeDay(year, MonthFromTime(this.date), DateFromTime(this.date));
1226 result = MakeDate(day, TimeWithinDay(this.date));
1227 result = internalUTC(result);
1229 this.date = TimeClip(result);
1234 // private static final int
1235 // Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6
1239 private static java.util.TimeZone thisTimeZone;
1240 private static double LocalTZA;
1241 private static java.text.DateFormat timeZoneFormatter;
1242 private static java.text.DateFormat localeDateTimeFormatter;
1243 private static java.text.DateFormat localeDateFormatter;
1244 private static java.text.DateFormat localeTimeFormatter;
1246 private double date;
1248 public long getRawTime() { return (long)this.date; }