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