2be8bcb220a7f3ed91ea1fb6943fa79398d5e4a7
[platform/upstream/v8.git] / src / date.js
1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 var $createDate;
6
7 // -------------------------------------------------------------------
8
9 (function(global, utils) {
10
11 "use strict";
12
13 %CheckIsBootstrapping();
14
15 // -------------------------------------------------------------------
16 // Imports
17
18 var GlobalDate = global.Date;
19 var InternalArray = utils.InternalArray;
20 var IsFinite;
21 var MathAbs;
22 var MathFloor;
23 var ToNumber;
24 var ToString;
25
26 utils.Import(function(from) {
27   IsFinite = from.IsFinite;
28   MathAbs = from.MathAbs;
29   MathFloor = from.MathFloor;
30   ToNumber = from.ToNumber;
31   ToString = from.ToString;
32 });
33
34 // -------------------------------------------------------------------
35
36 // This file contains date support implemented in JavaScript.
37
38 var timezone_cache_time = NAN;
39 var timezone_cache_timezone;
40
41 function LocalTimezone(t) {
42   if (NUMBER_IS_NAN(t)) return "";
43   CheckDateCacheCurrent();
44   if (t == timezone_cache_time) {
45     return timezone_cache_timezone;
46   }
47   var timezone = %DateLocalTimezone(t);
48   timezone_cache_time = t;
49   timezone_cache_timezone = timezone;
50   return timezone;
51 }
52
53
54 function UTC(time) {
55   if (NUMBER_IS_NAN(time)) return time;
56   // local_time_offset is needed before the call to DaylightSavingsOffset,
57   // so it may be uninitialized.
58   return %DateToUTC(time);
59 }
60
61
62 // ECMA 262 - 15.9.1.11
63 function MakeTime(hour, min, sec, ms) {
64   if (!IsFinite(hour)) return NAN;
65   if (!IsFinite(min)) return NAN;
66   if (!IsFinite(sec)) return NAN;
67   if (!IsFinite(ms)) return NAN;
68   return TO_INTEGER(hour) * msPerHour
69       + TO_INTEGER(min) * msPerMinute
70       + TO_INTEGER(sec) * msPerSecond
71       + TO_INTEGER(ms);
72 }
73
74
75 // ECMA 262 - 15.9.1.12
76 function TimeInYear(year) {
77   return DaysInYear(year) * msPerDay;
78 }
79
80
81 // Compute number of days given a year, month, date.
82 // Note that month and date can lie outside the normal range.
83 //   For example:
84 //     MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
85 //     MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
86 //     MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
87 function MakeDay(year, month, date) {
88   if (!IsFinite(year) || !IsFinite(month) || !IsFinite(date)) return NAN;
89
90   // Convert to integer and map -0 to 0.
91   year = TO_INTEGER_MAP_MINUS_ZERO(year);
92   month = TO_INTEGER_MAP_MINUS_ZERO(month);
93   date = TO_INTEGER_MAP_MINUS_ZERO(date);
94
95   if (year < kMinYear || year > kMaxYear ||
96       month < kMinMonth || month > kMaxMonth) {
97     return NAN;
98   }
99
100   // Now we rely on year and month being SMIs.
101   return %DateMakeDay(year | 0, month | 0) + date - 1;
102 }
103
104
105 // ECMA 262 - 15.9.1.13
106 function MakeDate(day, time) {
107   var time = day * msPerDay + time;
108   // Some of our runtime funtions for computing UTC(time) rely on
109   // times not being significantly larger than MAX_TIME_MS. If there
110   // is no way that the time can be within range even after UTC
111   // conversion we return NaN immediately instead of relying on
112   // TimeClip to do it.
113   if (MathAbs(time) > MAX_TIME_BEFORE_UTC) return NAN;
114   return time;
115 }
116
117
118 // ECMA 262 - 15.9.1.14
119 function TimeClip(time) {
120   if (!IsFinite(time)) return NAN;
121   if (MathAbs(time) > MAX_TIME_MS) return NAN;
122   return TO_INTEGER(time);
123 }
124
125
126 // The Date cache is used to limit the cost of parsing the same Date
127 // strings over and over again.
128 var Date_cache = {
129   // Cached time value.
130   time: 0,
131   // String input for which the cached time is valid.
132   string: null
133 };
134
135
136 function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
137   if (!%_IsConstructCall()) {
138     // ECMA 262 - 15.9.2
139     return %_CallFunction(new GlobalDate(), DateToString);
140   }
141
142   // ECMA 262 - 15.9.3
143   var argc = %_ArgumentsLength();
144   var value;
145   if (argc == 0) {
146     value = %DateCurrentTime();
147     SET_UTC_DATE_VALUE(this, value);
148   } else if (argc == 1) {
149     if (IS_NUMBER(year)) {
150       value = year;
151     } else if (IS_STRING(year)) {
152       // Probe the Date cache. If we already have a time value for the
153       // given time, we re-use that instead of parsing the string again.
154       CheckDateCacheCurrent();
155       var cache = Date_cache;
156       if (cache.string === year) {
157         value = cache.time;
158       } else {
159         value = DateParse(year);
160         if (!NUMBER_IS_NAN(value)) {
161           cache.time = value;
162           cache.string = year;
163         }
164       }
165
166     } else {
167       // According to ECMA 262, no hint should be given for this
168       // conversion. However, ToPrimitive defaults to STRING_HINT for
169       // Date objects which will lose precision when the Date
170       // constructor is called with another Date object as its
171       // argument. We therefore use NUMBER_HINT for the conversion,
172       // which is the default for everything else than Date objects.
173       // This makes us behave like KJS and SpiderMonkey.
174       var time = $toPrimitive(year, NUMBER_HINT);
175       value = IS_STRING(time) ? DateParse(time) : ToNumber(time);
176     }
177     SET_UTC_DATE_VALUE(this, value);
178   } else {
179     year = ToNumber(year);
180     month = ToNumber(month);
181     date = argc > 2 ? ToNumber(date) : 1;
182     hours = argc > 3 ? ToNumber(hours) : 0;
183     minutes = argc > 4 ? ToNumber(minutes) : 0;
184     seconds = argc > 5 ? ToNumber(seconds) : 0;
185     ms = argc > 6 ? ToNumber(ms) : 0;
186     year = (!NUMBER_IS_NAN(year) &&
187             0 <= TO_INTEGER(year) &&
188             TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
189     var day = MakeDay(year, month, date);
190     var time = MakeTime(hours, minutes, seconds, ms);
191     value = MakeDate(day, time);
192     SET_LOCAL_DATE_VALUE(this, value);
193   }
194 }
195
196
197 var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
198 var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
199               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
200
201
202 function TwoDigitString(value) {
203   return value < 10 ? "0" + value : "" + value;
204 }
205
206
207 function DateString(date) {
208   CHECK_DATE(date);
209   return WeekDays[LOCAL_WEEKDAY(date)] + ' '
210       + Months[LOCAL_MONTH(date)] + ' '
211       + TwoDigitString(LOCAL_DAY(date)) + ' '
212       + LOCAL_YEAR(date);
213 }
214
215
216 var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
217     'Thursday', 'Friday', 'Saturday'];
218 var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June',
219     'July', 'August', 'September', 'October', 'November', 'December'];
220
221
222 function LongDateString(date) {
223   CHECK_DATE(date);
224   return LongWeekDays[LOCAL_WEEKDAY(date)] + ', '
225       + LongMonths[LOCAL_MONTH(date)] + ' '
226       + TwoDigitString(LOCAL_DAY(date)) + ', '
227       + LOCAL_YEAR(date);
228 }
229
230
231 function TimeString(date) {
232   CHECK_DATE(date);
233   return TwoDigitString(LOCAL_HOUR(date)) + ':'
234       + TwoDigitString(LOCAL_MIN(date)) + ':'
235       + TwoDigitString(LOCAL_SEC(date));
236 }
237
238
239 function TimeStringUTC(date) {
240   CHECK_DATE(date);
241   return TwoDigitString(UTC_HOUR(date)) + ':'
242       + TwoDigitString(UTC_MIN(date)) + ':'
243       + TwoDigitString(UTC_SEC(date));
244 }
245
246
247 function LocalTimezoneString(date) {
248   CHECK_DATE(date);
249   var timezone = LocalTimezone(UTC_DATE_VALUE(date));
250
251   var timezoneOffset = -TIMEZONE_OFFSET(date);
252   var sign = (timezoneOffset >= 0) ? 1 : -1;
253   var hours = MathFloor((sign * timezoneOffset)/60);
254   var min   = MathFloor((sign * timezoneOffset)%60);
255   var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
256       TwoDigitString(hours) + TwoDigitString(min);
257   return gmt + ' (' +  timezone + ')';
258 }
259
260
261 function DatePrintString(date) {
262   CHECK_DATE(date);
263   return DateString(date) + ' ' + TimeString(date);
264 }
265
266 // -------------------------------------------------------------------
267
268 // Reused output buffer. Used when parsing date strings.
269 var parse_buffer = new InternalArray(8);
270
271 // ECMA 262 - 15.9.4.2
272 function DateParse(string) {
273   var arr = %DateParseString(ToString(string), parse_buffer);
274   if (IS_NULL(arr)) return NAN;
275
276   var day = MakeDay(arr[0], arr[1], arr[2]);
277   var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
278   var date = MakeDate(day, time);
279
280   if (IS_NULL(arr[7])) {
281     return TimeClip(UTC(date));
282   } else {
283     return TimeClip(date - arr[7] * 1000);
284   }
285 }
286
287
288 // ECMA 262 - 15.9.4.3
289 function DateUTC(year, month, date, hours, minutes, seconds, ms) {
290   year = ToNumber(year);
291   month = ToNumber(month);
292   var argc = %_ArgumentsLength();
293   date = argc > 2 ? ToNumber(date) : 1;
294   hours = argc > 3 ? ToNumber(hours) : 0;
295   minutes = argc > 4 ? ToNumber(minutes) : 0;
296   seconds = argc > 5 ? ToNumber(seconds) : 0;
297   ms = argc > 6 ? ToNumber(ms) : 0;
298   year = (!NUMBER_IS_NAN(year) &&
299           0 <= TO_INTEGER(year) &&
300           TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
301   var day = MakeDay(year, month, date);
302   var time = MakeTime(hours, minutes, seconds, ms);
303   return TimeClip(MakeDate(day, time));
304 }
305
306
307 // ECMA 262 - 15.9.4.4
308 function DateNow() {
309   return %DateCurrentTime();
310 }
311
312
313 // ECMA 262 - 15.9.5.2
314 function DateToString() {
315   CHECK_DATE(this);
316   var t = UTC_DATE_VALUE(this)
317   if (NUMBER_IS_NAN(t)) return kInvalidDate;
318   var time_zone_string = LocalTimezoneString(this)
319   return DatePrintString(this) + time_zone_string;
320 }
321
322
323 // ECMA 262 - 15.9.5.3
324 function DateToDateString() {
325   CHECK_DATE(this);
326   var t = UTC_DATE_VALUE(this);
327   if (NUMBER_IS_NAN(t)) return kInvalidDate;
328   return DateString(this);
329 }
330
331
332 // ECMA 262 - 15.9.5.4
333 function DateToTimeString() {
334   CHECK_DATE(this);
335   var t = UTC_DATE_VALUE(this);
336   if (NUMBER_IS_NAN(t)) return kInvalidDate;
337   var time_zone_string = LocalTimezoneString(this);
338   return TimeString(this) + time_zone_string;
339 }
340
341
342 // ECMA 262 - 15.9.5.5
343 function DateToLocaleString() {
344   CHECK_DATE(this);
345   return %_CallFunction(this, DateToString);
346 }
347
348
349 // ECMA 262 - 15.9.5.6
350 function DateToLocaleDateString() {
351   CHECK_DATE(this);
352   var t = UTC_DATE_VALUE(this);
353   if (NUMBER_IS_NAN(t)) return kInvalidDate;
354   return LongDateString(this);
355 }
356
357
358 // ECMA 262 - 15.9.5.7
359 function DateToLocaleTimeString() {
360   CHECK_DATE(this);
361   var t = UTC_DATE_VALUE(this);
362   if (NUMBER_IS_NAN(t)) return kInvalidDate;
363   return TimeString(this);
364 }
365
366
367 // ECMA 262 - 15.9.5.8
368 function DateValueOf() {
369   CHECK_DATE(this);
370   return UTC_DATE_VALUE(this);
371 }
372
373
374 // ECMA 262 - 15.9.5.9
375 function DateGetTime() {
376   CHECK_DATE(this);
377   return UTC_DATE_VALUE(this);
378 }
379
380
381 // ECMA 262 - 15.9.5.10
382 function DateGetFullYear() {
383   CHECK_DATE(this);
384   return LOCAL_YEAR(this);
385 }
386
387
388 // ECMA 262 - 15.9.5.11
389 function DateGetUTCFullYear() {
390   CHECK_DATE(this);
391   return UTC_YEAR(this);
392 }
393
394
395 // ECMA 262 - 15.9.5.12
396 function DateGetMonth() {
397   CHECK_DATE(this);
398   return LOCAL_MONTH(this);
399 }
400
401
402 // ECMA 262 - 15.9.5.13
403 function DateGetUTCMonth() {
404   CHECK_DATE(this);
405   return UTC_MONTH(this);
406 }
407
408
409 // ECMA 262 - 15.9.5.14
410 function DateGetDate() {
411   CHECK_DATE(this);
412   return LOCAL_DAY(this);
413 }
414
415
416 // ECMA 262 - 15.9.5.15
417 function DateGetUTCDate() {
418   CHECK_DATE(this);
419   return UTC_DAY(this);
420 }
421
422
423 // ECMA 262 - 15.9.5.16
424 function DateGetDay() {
425   CHECK_DATE(this);
426   return LOCAL_WEEKDAY(this);
427 }
428
429
430 // ECMA 262 - 15.9.5.17
431 function DateGetUTCDay() {
432   CHECK_DATE(this);
433   return UTC_WEEKDAY(this);
434 }
435
436
437 // ECMA 262 - 15.9.5.18
438 function DateGetHours() {
439   CHECK_DATE(this);
440   return LOCAL_HOUR(this);
441 }
442
443
444 // ECMA 262 - 15.9.5.19
445 function DateGetUTCHours() {
446   CHECK_DATE(this);
447   return UTC_HOUR(this);
448 }
449
450
451 // ECMA 262 - 15.9.5.20
452 function DateGetMinutes() {
453   CHECK_DATE(this);
454   return LOCAL_MIN(this);
455 }
456
457
458 // ECMA 262 - 15.9.5.21
459 function DateGetUTCMinutes() {
460   CHECK_DATE(this);
461   return UTC_MIN(this);
462 }
463
464
465 // ECMA 262 - 15.9.5.22
466 function DateGetSeconds() {
467   CHECK_DATE(this);
468   return LOCAL_SEC(this);
469 }
470
471
472 // ECMA 262 - 15.9.5.23
473 function DateGetUTCSeconds() {
474   CHECK_DATE(this);
475   return UTC_SEC(this)
476 }
477
478
479 // ECMA 262 - 15.9.5.24
480 function DateGetMilliseconds() {
481   CHECK_DATE(this);
482   return LOCAL_MS(this);
483 }
484
485
486 // ECMA 262 - 15.9.5.25
487 function DateGetUTCMilliseconds() {
488   CHECK_DATE(this);
489   return UTC_MS(this);
490 }
491
492
493 // ECMA 262 - 15.9.5.26
494 function DateGetTimezoneOffset() {
495   CHECK_DATE(this);
496   return TIMEZONE_OFFSET(this);
497 }
498
499
500 // ECMA 262 - 15.9.5.27
501 function DateSetTime(ms) {
502   CHECK_DATE(this);
503   SET_UTC_DATE_VALUE(this, ToNumber(ms));
504   return UTC_DATE_VALUE(this);
505 }
506
507
508 // ECMA 262 - 15.9.5.28
509 function DateSetMilliseconds(ms) {
510   CHECK_DATE(this);
511   var t = LOCAL_DATE_VALUE(this);
512   ms = ToNumber(ms);
513   var time = MakeTime(LOCAL_HOUR(this), LOCAL_MIN(this), LOCAL_SEC(this), ms);
514   return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
515 }
516
517
518 // ECMA 262 - 15.9.5.29
519 function DateSetUTCMilliseconds(ms) {
520   CHECK_DATE(this);
521   var t = UTC_DATE_VALUE(this);
522   ms = ToNumber(ms);
523   var time = MakeTime(UTC_HOUR(this),
524                       UTC_MIN(this),
525                       UTC_SEC(this),
526                       ms);
527   return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
528 }
529
530
531 // ECMA 262 - 15.9.5.30
532 function DateSetSeconds(sec, ms) {
533   CHECK_DATE(this);
534   var t = LOCAL_DATE_VALUE(this);
535   sec = ToNumber(sec);
536   ms = %_ArgumentsLength() < 2 ? LOCAL_MS(this) : ToNumber(ms);
537   var time = MakeTime(LOCAL_HOUR(this), LOCAL_MIN(this), sec, ms);
538   return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
539 }
540
541
542 // ECMA 262 - 15.9.5.31
543 function DateSetUTCSeconds(sec, ms) {
544   CHECK_DATE(this);
545   var t = UTC_DATE_VALUE(this);
546   sec = ToNumber(sec);
547   ms = %_ArgumentsLength() < 2 ? UTC_MS(this) : ToNumber(ms);
548   var time = MakeTime(UTC_HOUR(this), UTC_MIN(this), sec, ms);
549   return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
550 }
551
552
553 // ECMA 262 - 15.9.5.33
554 function DateSetMinutes(min, sec, ms) {
555   CHECK_DATE(this);
556   var t = LOCAL_DATE_VALUE(this);
557   min = ToNumber(min);
558   var argc = %_ArgumentsLength();
559   sec = argc < 2 ? LOCAL_SEC(this) : ToNumber(sec);
560   ms = argc < 3 ? LOCAL_MS(this) : ToNumber(ms);
561   var time = MakeTime(LOCAL_HOUR(this), min, sec, ms);
562   return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
563 }
564
565
566 // ECMA 262 - 15.9.5.34
567 function DateSetUTCMinutes(min, sec, ms) {
568   CHECK_DATE(this);
569   var t = UTC_DATE_VALUE(this);
570   min = ToNumber(min);
571   var argc = %_ArgumentsLength();
572   sec = argc < 2 ? UTC_SEC(this) : ToNumber(sec);
573   ms = argc < 3 ? UTC_MS(this) : ToNumber(ms);
574   var time = MakeTime(UTC_HOUR(this), min, sec, ms);
575   return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
576 }
577
578
579 // ECMA 262 - 15.9.5.35
580 function DateSetHours(hour, min, sec, ms) {
581   CHECK_DATE(this);
582   var t = LOCAL_DATE_VALUE(this);
583   hour = ToNumber(hour);
584   var argc = %_ArgumentsLength();
585   min = argc < 2 ? LOCAL_MIN(this) : ToNumber(min);
586   sec = argc < 3 ? LOCAL_SEC(this) : ToNumber(sec);
587   ms = argc < 4 ? LOCAL_MS(this) : ToNumber(ms);
588   var time = MakeTime(hour, min, sec, ms);
589   return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
590 }
591
592
593 // ECMA 262 - 15.9.5.34
594 function DateSetUTCHours(hour, min, sec, ms) {
595   CHECK_DATE(this);
596   var t = UTC_DATE_VALUE(this);
597   hour = ToNumber(hour);
598   var argc = %_ArgumentsLength();
599   min = argc < 2 ? UTC_MIN(this) : ToNumber(min);
600   sec = argc < 3 ? UTC_SEC(this) : ToNumber(sec);
601   ms = argc < 4 ? UTC_MS(this) : ToNumber(ms);
602   var time = MakeTime(hour, min, sec, ms);
603   return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
604 }
605
606
607 // ECMA 262 - 15.9.5.36
608 function DateSetDate(date) {
609   CHECK_DATE(this);
610   var t = LOCAL_DATE_VALUE(this);
611   date = ToNumber(date);
612   var day = MakeDay(LOCAL_YEAR(this), LOCAL_MONTH(this), date);
613   return SET_LOCAL_DATE_VALUE(this, MakeDate(day, LOCAL_TIME_IN_DAY(this)));
614 }
615
616
617 // ECMA 262 - 15.9.5.37
618 function DateSetUTCDate(date) {
619   CHECK_DATE(this);
620   var t = UTC_DATE_VALUE(this);
621   date = ToNumber(date);
622   var day = MakeDay(UTC_YEAR(this), UTC_MONTH(this), date);
623   return SET_UTC_DATE_VALUE(this, MakeDate(day, UTC_TIME_IN_DAY(this)));
624 }
625
626
627 // ECMA 262 - 15.9.5.38
628 function DateSetMonth(month, date) {
629   CHECK_DATE(this);
630   var t = LOCAL_DATE_VALUE(this);
631   month = ToNumber(month);
632   date = %_ArgumentsLength() < 2 ? LOCAL_DAY(this) : ToNumber(date);
633   var day = MakeDay(LOCAL_YEAR(this), month, date);
634   return SET_LOCAL_DATE_VALUE(this, MakeDate(day, LOCAL_TIME_IN_DAY(this)));
635 }
636
637
638 // ECMA 262 - 15.9.5.39
639 function DateSetUTCMonth(month, date) {
640   CHECK_DATE(this);
641   var t = UTC_DATE_VALUE(this);
642   month = ToNumber(month);
643   date = %_ArgumentsLength() < 2 ? UTC_DAY(this) : ToNumber(date);
644   var day = MakeDay(UTC_YEAR(this), month, date);
645   return SET_UTC_DATE_VALUE(this, MakeDate(day, UTC_TIME_IN_DAY(this)));
646 }
647
648
649 // ECMA 262 - 15.9.5.40
650 function DateSetFullYear(year, month, date) {
651   CHECK_DATE(this);
652   var t = LOCAL_DATE_VALUE(this);
653   year = ToNumber(year);
654   var argc = %_ArgumentsLength();
655   var time ;
656   if (NUMBER_IS_NAN(t)) {
657     month = argc < 2 ? 0 : ToNumber(month);
658     date = argc < 3 ? 1 : ToNumber(date);
659     time = 0;
660   } else {
661     month = argc < 2 ? LOCAL_MONTH(this) : ToNumber(month);
662     date = argc < 3 ? LOCAL_DAY(this) : ToNumber(date);
663     time = LOCAL_TIME_IN_DAY(this);
664   }
665   var day = MakeDay(year, month, date);
666   return SET_LOCAL_DATE_VALUE(this, MakeDate(day, time));
667 }
668
669
670 // ECMA 262 - 15.9.5.41
671 function DateSetUTCFullYear(year, month, date) {
672   CHECK_DATE(this);
673   var t = UTC_DATE_VALUE(this);
674   year = ToNumber(year);
675   var argc = %_ArgumentsLength();
676   var time ;
677   if (NUMBER_IS_NAN(t)) {
678     month = argc < 2 ? 0 : ToNumber(month);
679     date = argc < 3 ? 1 : ToNumber(date);
680     time = 0;
681   } else {
682     month = argc < 2 ? UTC_MONTH(this) : ToNumber(month);
683     date = argc < 3 ? UTC_DAY(this) : ToNumber(date);
684     time = UTC_TIME_IN_DAY(this);
685   }
686   var day = MakeDay(year, month, date);
687   return SET_UTC_DATE_VALUE(this, MakeDate(day, time));
688 }
689
690
691 // ECMA 262 - 15.9.5.42
692 function DateToUTCString() {
693   CHECK_DATE(this);
694   var t = UTC_DATE_VALUE(this);
695   if (NUMBER_IS_NAN(t)) return kInvalidDate;
696   // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
697   return WeekDays[UTC_WEEKDAY(this)] + ', '
698       + TwoDigitString(UTC_DAY(this)) + ' '
699       + Months[UTC_MONTH(this)] + ' '
700       + UTC_YEAR(this) + ' '
701       + TimeStringUTC(this) + ' GMT';
702 }
703
704
705 // ECMA 262 - B.2.4
706 function DateGetYear() {
707   CHECK_DATE(this);
708   return LOCAL_YEAR(this) - 1900;
709 }
710
711
712 // ECMA 262 - B.2.5
713 function DateSetYear(year) {
714   CHECK_DATE(this);
715   year = ToNumber(year);
716   if (NUMBER_IS_NAN(year)) return SET_UTC_DATE_VALUE(this, NAN);
717   year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
718       ? 1900 + TO_INTEGER(year) : year;
719   var t = LOCAL_DATE_VALUE(this);
720   var month, date, time;
721   if (NUMBER_IS_NAN(t))  {
722     month = 0;
723     date = 1;
724     time = 0;
725   } else {
726     month = LOCAL_MONTH(this);
727     date = LOCAL_DAY(this);
728     time = LOCAL_TIME_IN_DAY(this);
729   }
730   var day = MakeDay(year, month, date);
731   return SET_LOCAL_DATE_VALUE(this, MakeDate(day, time));
732 }
733
734
735 // ECMA 262 - B.2.6
736 //
737 // Notice that this does not follow ECMA 262 completely.  ECMA 262
738 // says that toGMTString should be the same Function object as
739 // toUTCString.  JSC does not do this, so for compatibility we do not
740 // do that either.  Instead, we create a new function whose name
741 // property will return toGMTString.
742 function DateToGMTString() {
743   return %_CallFunction(this, DateToUTCString);
744 }
745
746
747 function PadInt(n, digits) {
748   if (digits == 1) return n;
749   return n < %_MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
750 }
751
752
753 // ECMA 262 - 20.3.4.36
754 function DateToISOString() {
755   CHECK_DATE(this);
756   var t = UTC_DATE_VALUE(this);
757   if (NUMBER_IS_NAN(t)) throw MakeRangeError(kInvalidTimeValue);
758   var year = UTC_YEAR(this);
759   var year_string;
760   if (year >= 0 && year <= 9999) {
761     year_string = PadInt(year, 4);
762   } else {
763     if (year < 0) {
764       year_string = "-" + PadInt(-year, 6);
765     } else {
766       year_string = "+" + PadInt(year, 6);
767     }
768   }
769   return year_string +
770       '-' + PadInt(UTC_MONTH(this) + 1, 2) +
771       '-' + PadInt(UTC_DAY(this), 2) +
772       'T' + PadInt(UTC_HOUR(this), 2) +
773       ':' + PadInt(UTC_MIN(this), 2) +
774       ':' + PadInt(UTC_SEC(this), 2) +
775       '.' + PadInt(UTC_MS(this), 3) +
776       'Z';
777 }
778
779
780 function DateToJSON(key) {
781   var o = TO_OBJECT(this);
782   var tv = $defaultNumber(o);
783   if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
784     return null;
785   }
786   return o.toISOString();
787 }
788
789
790 var date_cache_version_holder;
791 var date_cache_version = NAN;
792
793
794 function CheckDateCacheCurrent() {
795   if (!date_cache_version_holder) {
796     date_cache_version_holder = %DateCacheVersion();
797     if (!date_cache_version_holder) return;
798   }
799   if (date_cache_version_holder[0] == date_cache_version) {
800     return;
801   }
802   date_cache_version = date_cache_version_holder[0];
803
804   // Reset the timezone cache:
805   timezone_cache_time = NAN;
806   timezone_cache_timezone = UNDEFINED;
807
808   // Reset the date cache:
809   Date_cache.time = NAN;
810   Date_cache.string = null;
811 }
812
813
814 function CreateDate(time) {
815   var date = new GlobalDate();
816   date.setTime(time);
817   return date;
818 }
819
820 // -------------------------------------------------------------------
821
822 %SetCode(GlobalDate, DateConstructor);
823 %FunctionSetPrototype(GlobalDate, new GlobalDate(NAN));
824
825 // Set up non-enumerable properties of the Date object itself.
826 utils.InstallFunctions(GlobalDate, DONT_ENUM, [
827   "UTC", DateUTC,
828   "parse", DateParse,
829   "now", DateNow
830 ]);
831
832 // Set up non-enumerable constructor property of the Date prototype object.
833 %AddNamedProperty(GlobalDate.prototype, "constructor", GlobalDate, DONT_ENUM);
834
835 // Set up non-enumerable functions of the Date prototype object and
836 // set their names.
837 utils.InstallFunctions(GlobalDate.prototype, DONT_ENUM, [
838   "toString", DateToString,
839   "toDateString", DateToDateString,
840   "toTimeString", DateToTimeString,
841   "toLocaleString", DateToLocaleString,
842   "toLocaleDateString", DateToLocaleDateString,
843   "toLocaleTimeString", DateToLocaleTimeString,
844   "valueOf", DateValueOf,
845   "getTime", DateGetTime,
846   "getFullYear", DateGetFullYear,
847   "getUTCFullYear", DateGetUTCFullYear,
848   "getMonth", DateGetMonth,
849   "getUTCMonth", DateGetUTCMonth,
850   "getDate", DateGetDate,
851   "getUTCDate", DateGetUTCDate,
852   "getDay", DateGetDay,
853   "getUTCDay", DateGetUTCDay,
854   "getHours", DateGetHours,
855   "getUTCHours", DateGetUTCHours,
856   "getMinutes", DateGetMinutes,
857   "getUTCMinutes", DateGetUTCMinutes,
858   "getSeconds", DateGetSeconds,
859   "getUTCSeconds", DateGetUTCSeconds,
860   "getMilliseconds", DateGetMilliseconds,
861   "getUTCMilliseconds", DateGetUTCMilliseconds,
862   "getTimezoneOffset", DateGetTimezoneOffset,
863   "setTime", DateSetTime,
864   "setMilliseconds", DateSetMilliseconds,
865   "setUTCMilliseconds", DateSetUTCMilliseconds,
866   "setSeconds", DateSetSeconds,
867   "setUTCSeconds", DateSetUTCSeconds,
868   "setMinutes", DateSetMinutes,
869   "setUTCMinutes", DateSetUTCMinutes,
870   "setHours", DateSetHours,
871   "setUTCHours", DateSetUTCHours,
872   "setDate", DateSetDate,
873   "setUTCDate", DateSetUTCDate,
874   "setMonth", DateSetMonth,
875   "setUTCMonth", DateSetUTCMonth,
876   "setFullYear", DateSetFullYear,
877   "setUTCFullYear", DateSetUTCFullYear,
878   "toGMTString", DateToGMTString,
879   "toUTCString", DateToUTCString,
880   "getYear", DateGetYear,
881   "setYear", DateSetYear,
882   "toISOString", DateToISOString,
883   "toJSON", DateToJSON
884 ]);
885
886 %InstallToContext(["create_date_fun", CreateDate]);
887
888 })