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