5df3afa98b7d5207c86c525f83070ad4c12919c3
[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 // 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint )
369 function DateToPrimitive(hint) {
370   if (!IS_SPEC_OBJECT(this)) {
371     throw MakeTypeError(kIncompatibleMethodReceiver,
372                         "Date.prototype [ @@toPrimitive ]", this);
373   }
374   if (hint === "default") {
375     hint = "string";
376   } else if (hint !== "number" && hint !== "string") {
377     throw MakeTypeError(kInvalidHint, hint);
378   }
379   return %OrdinaryToPrimitive(this, hint);
380 }
381
382
383 // ECMA 262 - 15.9.5.8
384 function DateValueOf() {
385   CHECK_DATE(this);
386   return UTC_DATE_VALUE(this);
387 }
388
389
390 // ECMA 262 - 15.9.5.9
391 function DateGetTime() {
392   CHECK_DATE(this);
393   return UTC_DATE_VALUE(this);
394 }
395
396
397 // ECMA 262 - 15.9.5.10
398 function DateGetFullYear() {
399   CHECK_DATE(this);
400   return LOCAL_YEAR(this);
401 }
402
403
404 // ECMA 262 - 15.9.5.11
405 function DateGetUTCFullYear() {
406   CHECK_DATE(this);
407   return UTC_YEAR(this);
408 }
409
410
411 // ECMA 262 - 15.9.5.12
412 function DateGetMonth() {
413   CHECK_DATE(this);
414   return LOCAL_MONTH(this);
415 }
416
417
418 // ECMA 262 - 15.9.5.13
419 function DateGetUTCMonth() {
420   CHECK_DATE(this);
421   return UTC_MONTH(this);
422 }
423
424
425 // ECMA 262 - 15.9.5.14
426 function DateGetDate() {
427   CHECK_DATE(this);
428   return LOCAL_DAY(this);
429 }
430
431
432 // ECMA 262 - 15.9.5.15
433 function DateGetUTCDate() {
434   CHECK_DATE(this);
435   return UTC_DAY(this);
436 }
437
438
439 // ECMA 262 - 15.9.5.16
440 function DateGetDay() {
441   CHECK_DATE(this);
442   return LOCAL_WEEKDAY(this);
443 }
444
445
446 // ECMA 262 - 15.9.5.17
447 function DateGetUTCDay() {
448   CHECK_DATE(this);
449   return UTC_WEEKDAY(this);
450 }
451
452
453 // ECMA 262 - 15.9.5.18
454 function DateGetHours() {
455   CHECK_DATE(this);
456   return LOCAL_HOUR(this);
457 }
458
459
460 // ECMA 262 - 15.9.5.19
461 function DateGetUTCHours() {
462   CHECK_DATE(this);
463   return UTC_HOUR(this);
464 }
465
466
467 // ECMA 262 - 15.9.5.20
468 function DateGetMinutes() {
469   CHECK_DATE(this);
470   return LOCAL_MIN(this);
471 }
472
473
474 // ECMA 262 - 15.9.5.21
475 function DateGetUTCMinutes() {
476   CHECK_DATE(this);
477   return UTC_MIN(this);
478 }
479
480
481 // ECMA 262 - 15.9.5.22
482 function DateGetSeconds() {
483   CHECK_DATE(this);
484   return LOCAL_SEC(this);
485 }
486
487
488 // ECMA 262 - 15.9.5.23
489 function DateGetUTCSeconds() {
490   CHECK_DATE(this);
491   return UTC_SEC(this)
492 }
493
494
495 // ECMA 262 - 15.9.5.24
496 function DateGetMilliseconds() {
497   CHECK_DATE(this);
498   return LOCAL_MS(this);
499 }
500
501
502 // ECMA 262 - 15.9.5.25
503 function DateGetUTCMilliseconds() {
504   CHECK_DATE(this);
505   return UTC_MS(this);
506 }
507
508
509 // ECMA 262 - 15.9.5.26
510 function DateGetTimezoneOffset() {
511   CHECK_DATE(this);
512   return TIMEZONE_OFFSET(this);
513 }
514
515
516 // ECMA 262 - 15.9.5.27
517 function DateSetTime(ms) {
518   CHECK_DATE(this);
519   SET_UTC_DATE_VALUE(this, ToNumber(ms));
520   return UTC_DATE_VALUE(this);
521 }
522
523
524 // ECMA 262 - 15.9.5.28
525 function DateSetMilliseconds(ms) {
526   CHECK_DATE(this);
527   var t = LOCAL_DATE_VALUE(this);
528   ms = ToNumber(ms);
529   var time = MakeTime(LOCAL_HOUR(this), LOCAL_MIN(this), LOCAL_SEC(this), ms);
530   return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
531 }
532
533
534 // ECMA 262 - 15.9.5.29
535 function DateSetUTCMilliseconds(ms) {
536   CHECK_DATE(this);
537   var t = UTC_DATE_VALUE(this);
538   ms = ToNumber(ms);
539   var time = MakeTime(UTC_HOUR(this),
540                       UTC_MIN(this),
541                       UTC_SEC(this),
542                       ms);
543   return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
544 }
545
546
547 // ECMA 262 - 15.9.5.30
548 function DateSetSeconds(sec, ms) {
549   CHECK_DATE(this);
550   var t = LOCAL_DATE_VALUE(this);
551   sec = ToNumber(sec);
552   ms = %_ArgumentsLength() < 2 ? LOCAL_MS(this) : ToNumber(ms);
553   var time = MakeTime(LOCAL_HOUR(this), LOCAL_MIN(this), sec, ms);
554   return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
555 }
556
557
558 // ECMA 262 - 15.9.5.31
559 function DateSetUTCSeconds(sec, ms) {
560   CHECK_DATE(this);
561   var t = UTC_DATE_VALUE(this);
562   sec = ToNumber(sec);
563   ms = %_ArgumentsLength() < 2 ? UTC_MS(this) : ToNumber(ms);
564   var time = MakeTime(UTC_HOUR(this), UTC_MIN(this), sec, ms);
565   return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
566 }
567
568
569 // ECMA 262 - 15.9.5.33
570 function DateSetMinutes(min, sec, ms) {
571   CHECK_DATE(this);
572   var t = LOCAL_DATE_VALUE(this);
573   min = ToNumber(min);
574   var argc = %_ArgumentsLength();
575   sec = argc < 2 ? LOCAL_SEC(this) : ToNumber(sec);
576   ms = argc < 3 ? LOCAL_MS(this) : ToNumber(ms);
577   var time = MakeTime(LOCAL_HOUR(this), min, sec, ms);
578   return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
579 }
580
581
582 // ECMA 262 - 15.9.5.34
583 function DateSetUTCMinutes(min, sec, ms) {
584   CHECK_DATE(this);
585   var t = UTC_DATE_VALUE(this);
586   min = ToNumber(min);
587   var argc = %_ArgumentsLength();
588   sec = argc < 2 ? UTC_SEC(this) : ToNumber(sec);
589   ms = argc < 3 ? UTC_MS(this) : ToNumber(ms);
590   var time = MakeTime(UTC_HOUR(this), min, sec, ms);
591   return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
592 }
593
594
595 // ECMA 262 - 15.9.5.35
596 function DateSetHours(hour, min, sec, ms) {
597   CHECK_DATE(this);
598   var t = LOCAL_DATE_VALUE(this);
599   hour = ToNumber(hour);
600   var argc = %_ArgumentsLength();
601   min = argc < 2 ? LOCAL_MIN(this) : ToNumber(min);
602   sec = argc < 3 ? LOCAL_SEC(this) : ToNumber(sec);
603   ms = argc < 4 ? LOCAL_MS(this) : ToNumber(ms);
604   var time = MakeTime(hour, min, sec, ms);
605   return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
606 }
607
608
609 // ECMA 262 - 15.9.5.34
610 function DateSetUTCHours(hour, min, sec, ms) {
611   CHECK_DATE(this);
612   var t = UTC_DATE_VALUE(this);
613   hour = ToNumber(hour);
614   var argc = %_ArgumentsLength();
615   min = argc < 2 ? UTC_MIN(this) : ToNumber(min);
616   sec = argc < 3 ? UTC_SEC(this) : ToNumber(sec);
617   ms = argc < 4 ? UTC_MS(this) : ToNumber(ms);
618   var time = MakeTime(hour, min, sec, ms);
619   return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
620 }
621
622
623 // ECMA 262 - 15.9.5.36
624 function DateSetDate(date) {
625   CHECK_DATE(this);
626   var t = LOCAL_DATE_VALUE(this);
627   date = ToNumber(date);
628   var day = MakeDay(LOCAL_YEAR(this), LOCAL_MONTH(this), date);
629   return SET_LOCAL_DATE_VALUE(this, MakeDate(day, LOCAL_TIME_IN_DAY(this)));
630 }
631
632
633 // ECMA 262 - 15.9.5.37
634 function DateSetUTCDate(date) {
635   CHECK_DATE(this);
636   var t = UTC_DATE_VALUE(this);
637   date = ToNumber(date);
638   var day = MakeDay(UTC_YEAR(this), UTC_MONTH(this), date);
639   return SET_UTC_DATE_VALUE(this, MakeDate(day, UTC_TIME_IN_DAY(this)));
640 }
641
642
643 // ECMA 262 - 15.9.5.38
644 function DateSetMonth(month, date) {
645   CHECK_DATE(this);
646   var t = LOCAL_DATE_VALUE(this);
647   month = ToNumber(month);
648   date = %_ArgumentsLength() < 2 ? LOCAL_DAY(this) : ToNumber(date);
649   var day = MakeDay(LOCAL_YEAR(this), month, date);
650   return SET_LOCAL_DATE_VALUE(this, MakeDate(day, LOCAL_TIME_IN_DAY(this)));
651 }
652
653
654 // ECMA 262 - 15.9.5.39
655 function DateSetUTCMonth(month, date) {
656   CHECK_DATE(this);
657   var t = UTC_DATE_VALUE(this);
658   month = ToNumber(month);
659   date = %_ArgumentsLength() < 2 ? UTC_DAY(this) : ToNumber(date);
660   var day = MakeDay(UTC_YEAR(this), month, date);
661   return SET_UTC_DATE_VALUE(this, MakeDate(day, UTC_TIME_IN_DAY(this)));
662 }
663
664
665 // ECMA 262 - 15.9.5.40
666 function DateSetFullYear(year, month, date) {
667   CHECK_DATE(this);
668   var t = LOCAL_DATE_VALUE(this);
669   year = ToNumber(year);
670   var argc = %_ArgumentsLength();
671   var time ;
672   if (NUMBER_IS_NAN(t)) {
673     month = argc < 2 ? 0 : ToNumber(month);
674     date = argc < 3 ? 1 : ToNumber(date);
675     time = 0;
676   } else {
677     month = argc < 2 ? LOCAL_MONTH(this) : ToNumber(month);
678     date = argc < 3 ? LOCAL_DAY(this) : ToNumber(date);
679     time = LOCAL_TIME_IN_DAY(this);
680   }
681   var day = MakeDay(year, month, date);
682   return SET_LOCAL_DATE_VALUE(this, MakeDate(day, time));
683 }
684
685
686 // ECMA 262 - 15.9.5.41
687 function DateSetUTCFullYear(year, month, date) {
688   CHECK_DATE(this);
689   var t = UTC_DATE_VALUE(this);
690   year = ToNumber(year);
691   var argc = %_ArgumentsLength();
692   var time ;
693   if (NUMBER_IS_NAN(t)) {
694     month = argc < 2 ? 0 : ToNumber(month);
695     date = argc < 3 ? 1 : ToNumber(date);
696     time = 0;
697   } else {
698     month = argc < 2 ? UTC_MONTH(this) : ToNumber(month);
699     date = argc < 3 ? UTC_DAY(this) : ToNumber(date);
700     time = UTC_TIME_IN_DAY(this);
701   }
702   var day = MakeDay(year, month, date);
703   return SET_UTC_DATE_VALUE(this, MakeDate(day, time));
704 }
705
706
707 // ECMA 262 - 15.9.5.42
708 function DateToUTCString() {
709   CHECK_DATE(this);
710   var t = UTC_DATE_VALUE(this);
711   if (NUMBER_IS_NAN(t)) return kInvalidDate;
712   // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
713   return WeekDays[UTC_WEEKDAY(this)] + ', '
714       + TwoDigitString(UTC_DAY(this)) + ' '
715       + Months[UTC_MONTH(this)] + ' '
716       + UTC_YEAR(this) + ' '
717       + TimeStringUTC(this) + ' GMT';
718 }
719
720
721 // ECMA 262 - B.2.4
722 function DateGetYear() {
723   CHECK_DATE(this);
724   return LOCAL_YEAR(this) - 1900;
725 }
726
727
728 // ECMA 262 - B.2.5
729 function DateSetYear(year) {
730   CHECK_DATE(this);
731   year = ToNumber(year);
732   if (NUMBER_IS_NAN(year)) return SET_UTC_DATE_VALUE(this, NAN);
733   year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
734       ? 1900 + TO_INTEGER(year) : year;
735   var t = LOCAL_DATE_VALUE(this);
736   var month, date, time;
737   if (NUMBER_IS_NAN(t))  {
738     month = 0;
739     date = 1;
740     time = 0;
741   } else {
742     month = LOCAL_MONTH(this);
743     date = LOCAL_DAY(this);
744     time = LOCAL_TIME_IN_DAY(this);
745   }
746   var day = MakeDay(year, month, date);
747   return SET_LOCAL_DATE_VALUE(this, MakeDate(day, time));
748 }
749
750
751 // ECMA 262 - B.2.6
752 //
753 // Notice that this does not follow ECMA 262 completely.  ECMA 262
754 // says that toGMTString should be the same Function object as
755 // toUTCString.  JSC does not do this, so for compatibility we do not
756 // do that either.  Instead, we create a new function whose name
757 // property will return toGMTString.
758 function DateToGMTString() {
759   return %_CallFunction(this, DateToUTCString);
760 }
761
762
763 function PadInt(n, digits) {
764   if (digits == 1) return n;
765   return n < %_MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
766 }
767
768
769 // ECMA 262 - 20.3.4.36
770 function DateToISOString() {
771   CHECK_DATE(this);
772   var t = UTC_DATE_VALUE(this);
773   if (NUMBER_IS_NAN(t)) throw MakeRangeError(kInvalidTimeValue);
774   var year = UTC_YEAR(this);
775   var year_string;
776   if (year >= 0 && year <= 9999) {
777     year_string = PadInt(year, 4);
778   } else {
779     if (year < 0) {
780       year_string = "-" + PadInt(-year, 6);
781     } else {
782       year_string = "+" + PadInt(year, 6);
783     }
784   }
785   return year_string +
786       '-' + PadInt(UTC_MONTH(this) + 1, 2) +
787       '-' + PadInt(UTC_DAY(this), 2) +
788       'T' + PadInt(UTC_HOUR(this), 2) +
789       ':' + PadInt(UTC_MIN(this), 2) +
790       ':' + PadInt(UTC_SEC(this), 2) +
791       '.' + PadInt(UTC_MS(this), 3) +
792       'Z';
793 }
794
795
796 // 20.3.4.37 Date.prototype.toJSON ( key )
797 function DateToJSON(key) {
798   var o = TO_OBJECT(this);
799   var tv = TO_PRIMITIVE_NUMBER(o);
800   if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
801     return null;
802   }
803   return o.toISOString();
804 }
805
806
807 var date_cache_version_holder;
808 var date_cache_version = NAN;
809
810
811 function CheckDateCacheCurrent() {
812   if (!date_cache_version_holder) {
813     date_cache_version_holder = %DateCacheVersion();
814     if (!date_cache_version_holder) return;
815   }
816   if (date_cache_version_holder[0] == date_cache_version) {
817     return;
818   }
819   date_cache_version = date_cache_version_holder[0];
820
821   // Reset the timezone cache:
822   timezone_cache_time = NAN;
823   timezone_cache_timezone = UNDEFINED;
824
825   // Reset the date cache:
826   Date_cache.time = NAN;
827   Date_cache.string = null;
828 }
829
830
831 function CreateDate(time) {
832   var date = new GlobalDate();
833   date.setTime(time);
834   return date;
835 }
836
837 // -------------------------------------------------------------------
838
839 %SetCode(GlobalDate, DateConstructor);
840 %FunctionSetPrototype(GlobalDate, new GlobalDate(NAN));
841
842 // Set up non-enumerable properties of the Date object itself.
843 utils.InstallFunctions(GlobalDate, DONT_ENUM, [
844   "UTC", DateUTC,
845   "parse", DateParse,
846   "now", DateNow
847 ]);
848
849 // Set up non-enumerable constructor property of the Date prototype object.
850 %AddNamedProperty(GlobalDate.prototype, "constructor", GlobalDate, DONT_ENUM);
851 utils.SetFunctionName(DateToPrimitive, toPrimitiveSymbol);
852 %AddNamedProperty(GlobalDate.prototype, toPrimitiveSymbol, DateToPrimitive,
853                   DONT_ENUM | READ_ONLY);
854
855 // Set up non-enumerable functions of the Date prototype object and
856 // set their names.
857 utils.InstallFunctions(GlobalDate.prototype, DONT_ENUM, [
858   "toString", DateToString,
859   "toDateString", DateToDateString,
860   "toTimeString", DateToTimeString,
861   "toLocaleString", DateToLocaleString,
862   "toLocaleDateString", DateToLocaleDateString,
863   "toLocaleTimeString", DateToLocaleTimeString,
864   "valueOf", DateValueOf,
865   "getTime", DateGetTime,
866   "getFullYear", DateGetFullYear,
867   "getUTCFullYear", DateGetUTCFullYear,
868   "getMonth", DateGetMonth,
869   "getUTCMonth", DateGetUTCMonth,
870   "getDate", DateGetDate,
871   "getUTCDate", DateGetUTCDate,
872   "getDay", DateGetDay,
873   "getUTCDay", DateGetUTCDay,
874   "getHours", DateGetHours,
875   "getUTCHours", DateGetUTCHours,
876   "getMinutes", DateGetMinutes,
877   "getUTCMinutes", DateGetUTCMinutes,
878   "getSeconds", DateGetSeconds,
879   "getUTCSeconds", DateGetUTCSeconds,
880   "getMilliseconds", DateGetMilliseconds,
881   "getUTCMilliseconds", DateGetUTCMilliseconds,
882   "getTimezoneOffset", DateGetTimezoneOffset,
883   "setTime", DateSetTime,
884   "setMilliseconds", DateSetMilliseconds,
885   "setUTCMilliseconds", DateSetUTCMilliseconds,
886   "setSeconds", DateSetSeconds,
887   "setUTCSeconds", DateSetUTCSeconds,
888   "setMinutes", DateSetMinutes,
889   "setUTCMinutes", DateSetUTCMinutes,
890   "setHours", DateSetHours,
891   "setUTCHours", DateSetUTCHours,
892   "setDate", DateSetDate,
893   "setUTCDate", DateSetUTCDate,
894   "setMonth", DateSetMonth,
895   "setUTCMonth", DateSetUTCMonth,
896   "setFullYear", DateSetFullYear,
897   "setUTCFullYear", DateSetUTCFullYear,
898   "toGMTString", DateToGMTString,
899   "toUTCString", DateToUTCString,
900   "getYear", DateGetYear,
901   "setYear", DateSetYear,
902   "toISOString", DateToISOString,
903   "toJSON", DateToJSON
904 ]);
905
906 %InstallToContext(["create_date_fun", CreateDate]);
907
908 })