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