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