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