date.js 23.3 KB
Newer Older
1
// Copyright 2006-2008 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


29 30
// This file relies on the fact that the following declarations have been made
// in v8natives.js:
31
// var $isFinite = GlobalIsFinite;
32

33 34 35 36 37 38 39
// -------------------------------------------------------------------

// This file contains date support implemented in JavaScript.

// Keep reference to original values of some global properties.  This
// has the added benefit that the code in this file is isolated from
// changes to these properties.
40
var $Date = global.Date;
41

42 43 44 45 46
// Helper function to throw error.
function ThrowDateTypeError() {
  throw new $TypeError('this is not a Date object.');
}

47 48 49 50 51

var timezone_cache_time = $NaN;
var timezone_cache_timezone;

function LocalTimezone(t) {
52
  if (NUMBER_IS_NAN(t)) return "";
53
  if (t == timezone_cache_time) {
54 55
    return timezone_cache_timezone;
  }
56
  var timezone = %DateLocalTimezone(t);
57 58 59
  timezone_cache_time = t;
  timezone_cache_timezone = timezone;
  return timezone;
60
}
61 62 63


function UTC(time) {
64
  if (NUMBER_IS_NAN(time)) return time;
65 66
  // local_time_offset is needed before the call to DaylightSavingsOffset,
  // so it may be uninitialized.
67
  return %DateToUTC(time);
68
}
69 70 71 72 73 74 75 76 77 78 79 80


// ECMA 262 - 15.9.1.11
function MakeTime(hour, min, sec, ms) {
  if (!$isFinite(hour)) return $NaN;
  if (!$isFinite(min)) return $NaN;
  if (!$isFinite(sec)) return $NaN;
  if (!$isFinite(ms)) return $NaN;
  return TO_INTEGER(hour) * msPerHour
      + TO_INTEGER(min) * msPerMinute
      + TO_INTEGER(sec) * msPerSecond
      + TO_INTEGER(ms);
81
}
82 83 84 85 86


// ECMA 262 - 15.9.1.12
function TimeInYear(year) {
  return DaysInYear(year) * msPerDay;
87
}
88 89 90 91 92 93 94 95 96 97 98


// Compute number of days given a year, month, date.
// Note that month and date can lie outside the normal range.
//   For example:
//     MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
//     MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
//     MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
function MakeDay(year, month, date) {
  if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return $NaN;

99 100 101 102
  // Convert to integer and map -0 to 0.
  year = TO_INTEGER_MAP_MINUS_ZERO(year);
  month = TO_INTEGER_MAP_MINUS_ZERO(month);
  date = TO_INTEGER_MAP_MINUS_ZERO(date);
103

104
  if (year < kMinYear || year > kMaxYear ||
105
      month < kMinMonth || month > kMaxMonth) {
106
    return $NaN;
107 108
  }

109 110
  // Now we rely on year and month being SMIs.
  return %DateMakeDay(year, month) + date - 1;
111
}
112 113 114 115


// ECMA 262 - 15.9.1.13
function MakeDate(day, time) {
116 117 118 119 120 121 122 123
  var time = day * msPerDay + time;
  // Some of our runtime funtions for computing UTC(time) rely on
  // times not being significantly larger than MAX_TIME_MS. If there
  // is no way that the time can be within range even after UTC
  // conversion we return NaN immediately instead of relying on
  // TimeClip to do it.
  if ($abs(time) > MAX_TIME_BEFORE_UTC) return $NaN;
  return time;
124
}
125 126 127 128 129


// ECMA 262 - 15.9.1.14
function TimeClip(time) {
  if (!$isFinite(time)) return $NaN;
130
  if ($abs(time) > MAX_TIME_MS) return $NaN;
131
  return TO_INTEGER(time);
132
}
133 134


135 136 137 138 139 140 141 142 143 144
// The Date cache is used to limit the cost of parsing the same Date
// strings over and over again.
var Date_cache = {
  // Cached time value.
  time: $NaN,
  // String input for which the cached time is valid.
  string: null
};


145
%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
146 147 148 149 150 151 152 153 154 155
  if (!%_IsConstructCall()) {
    // ECMA 262 - 15.9.2
    return (new $Date()).toString();
  }

  // ECMA 262 - 15.9.3
  var argc = %_ArgumentsLength();
  var value;
  if (argc == 0) {
    value = %DateCurrentTime();
156
    SET_UTC_DATE_VALUE(this, value);
157 158
  } else if (argc == 1) {
    if (IS_NUMBER(year)) {
159
      value = year;
160 161 162 163 164 165 166 167
    } else if (IS_STRING(year)) {
      // Probe the Date cache. If we already have a time value for the
      // given time, we re-use that instead of parsing the string again.
      var cache = Date_cache;
      if (cache.string === year) {
        value = cache.time;
      } else {
        value = DateParse(year);
168 169 170 171
        if (!NUMBER_IS_NAN(value)) {
          cache.time = value;
          cache.string = year;
        }
172 173
      }

174
    } else {
175
      // According to ECMA 262, no hint should be given for this
176 177
      // conversion. However, ToPrimitive defaults to STRING_HINT for
      // Date objects which will lose precision when the Date
178
      // constructor is called with another Date object as its
179 180 181
      // argument. We therefore use NUMBER_HINT for the conversion,
      // which is the default for everything else than Date objects.
      // This makes us behave like KJS and SpiderMonkey.
182
      var time = ToPrimitive(year, NUMBER_HINT);
183
      value = IS_STRING(time) ? DateParse(time) : ToNumber(time);
184
    }
185
    SET_UTC_DATE_VALUE(this, value);
186
  } else {
187 188 189 190 191 192 193
    year = ToNumber(year);
    month = ToNumber(month);
    date = argc > 2 ? ToNumber(date) : 1;
    hours = argc > 3 ? ToNumber(hours) : 0;
    minutes = argc > 4 ? ToNumber(minutes) : 0;
    seconds = argc > 5 ? ToNumber(seconds) : 0;
    ms = argc > 6 ? ToNumber(ms) : 0;
194 195 196
    year = (!NUMBER_IS_NAN(year) &&
            0 <= TO_INTEGER(year) &&
            TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
197 198
    var day = MakeDay(year, month, date);
    var time = MakeTime(hours, minutes, seconds, ms);
199 200
    value = MakeDate(day, time);
    SET_LOCAL_DATE_VALUE(this, value);
201 202 203 204 205 206 207 208
  }
});


%FunctionSetPrototype($Date, new $Date($NaN));


var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
209 210
var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
              'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
211 212 213 214


function TwoDigitString(value) {
  return value < 10 ? "0" + value : "" + value;
215
}
216 217


218 219 220 221 222
function DateString(date) {
  return WeekDays[LOCAL_WEEKDAY(date)] + ' '
      + Months[LOCAL_MONTH(date)] + ' '
      + TwoDigitString(LOCAL_DAY(date)) + ' '
      + LOCAL_YEAR(date);
223
}
224 225


226 227 228 229
var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
    'Thursday', 'Friday', 'Saturday'];
var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June',
    'July', 'August', 'September', 'October', 'November', 'December'];
230 231


232 233 234 235 236
function LongDateString(date) {
  return LongWeekDays[LOCAL_WEEKDAY(date)] + ', '
      + LongMonths[LOCAL_MONTH(date)] + ' '
      + TwoDigitString(LOCAL_DAY(date)) + ', '
      + LOCAL_YEAR(date);
237 238 239
}


240 241 242 243
function TimeString(date) {
  return TwoDigitString(LOCAL_HOUR(date)) + ':'
      + TwoDigitString(LOCAL_MIN(date)) + ':'
      + TwoDigitString(LOCAL_SEC(date));
244
}
245 246


247 248 249 250 251 252
function TimeStringUTC(date) {
  return TwoDigitString(UTC_HOUR(date)) + ':'
      + TwoDigitString(UTC_MIN(date)) + ':'
      + TwoDigitString(UTC_SEC(date));
}

253

254 255 256 257
function LocalTimezoneString(date) {
  var timezone = LocalTimezone(UTC_DATE_VALUE(date));

  var timezoneOffset = -TIMEZONE_OFFSET(date);
258
  var sign = (timezoneOffset >= 0) ? 1 : -1;
259 260
  var hours = FLOOR((sign * timezoneOffset)/60);
  var min   = FLOOR((sign * timezoneOffset)%60);
261 262
  var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
      TwoDigitString(hours) + TwoDigitString(min);
263
  return gmt + ' (' +  timezone + ')';
264
}
265 266


267 268
function DatePrintString(date) {
  return DateString(date) + ' ' + TimeString(date);
269
}
270 271 272

// -------------------------------------------------------------------

273
// Reused output buffer. Used when parsing date strings.
274
var parse_buffer = $Array(8);
275 276 277

// ECMA 262 - 15.9.4.2
function DateParse(string) {
278
  var arr = %DateParseString(ToString(string), parse_buffer);
279 280 281
  if (IS_NULL(arr)) return $NaN;

  var day = MakeDay(arr[0], arr[1], arr[2]);
282
  var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
283
  var date = MakeDate(day, time);
284

285
  if (IS_NULL(arr[7])) {
286 287
    return TimeClip(UTC(date));
  } else {
288
    return TimeClip(date - arr[7] * 1000);
289
  }
290
}
291 292 293 294 295 296 297 298 299 300 301 302


// ECMA 262 - 15.9.4.3
function DateUTC(year, month, date, hours, minutes, seconds, ms) {
  year = ToNumber(year);
  month = ToNumber(month);
  var argc = %_ArgumentsLength();
  date = argc > 2 ? ToNumber(date) : 1;
  hours = argc > 3 ? ToNumber(hours) : 0;
  minutes = argc > 4 ? ToNumber(minutes) : 0;
  seconds = argc > 5 ? ToNumber(seconds) : 0;
  ms = argc > 6 ? ToNumber(ms) : 0;
303 304 305
  year = (!NUMBER_IS_NAN(year) &&
          0 <= TO_INTEGER(year) &&
          TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
306 307
  var day = MakeDay(year, month, date);
  var time = MakeTime(hours, minutes, seconds, ms);
308
  return TimeClip(MakeDate(day, time));
309
}
310 311 312 313 314


// Mozilla-specific extension. Returns the number of milliseconds
// elapsed since 1 January 1970 00:00:00 UTC.
function DateNow() {
315
  return %DateCurrentTime();
316
}
317 318 319 320


// ECMA 262 - 15.9.5.2
function DateToString() {
321 322
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this)
323
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
324 325
  var time_zone_string = LocalTimezoneString(this)
  return DatePrintString(this) + time_zone_string;
326
}
327 328 329 330


// ECMA 262 - 15.9.5.3
function DateToDateString() {
331 332
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
333
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
334
  return DateString(this);
335
}
336 337 338 339


// ECMA 262 - 15.9.5.4
function DateToTimeString() {
340 341
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
342
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
343 344
  var time_zone_string = LocalTimezoneString(this);
  return TimeString(this) + time_zone_string;
345 346 347 348 349
}


// ECMA 262 - 15.9.5.5
function DateToLocaleString() {
350
  return %_CallFunction(this, DateToString);
351 352 353 354 355
}


// ECMA 262 - 15.9.5.6
function DateToLocaleDateString() {
356 357
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
358
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
359
  return LongDateString(this);
360
}
361 362


363 364
// ECMA 262 - 15.9.5.7
function DateToLocaleTimeString() {
365 366
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
367
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
368
  return TimeString(this);
369 370 371 372 373
}


// ECMA 262 - 15.9.5.8
function DateValueOf() {
374 375
  CHECK_DATE(this);
  return UTC_DATE_VALUE(this);
376
}
377 378


379 380
// ECMA 262 - 15.9.5.9
function DateGetTime() {
381 382
  CHECK_DATE(this);
  return UTC_DATE_VALUE(this);
383 384 385 386 387
}


// ECMA 262 - 15.9.5.10
function DateGetFullYear() {
388 389
  CHECK_DATE(this);
  return LOCAL_YEAR(this);
390
}
391 392 393 394


// ECMA 262 - 15.9.5.11
function DateGetUTCFullYear() {
395 396
  CHECK_DATE(this);
  return UTC_YEAR(this);
397
}
398 399 400 401


// ECMA 262 - 15.9.5.12
function DateGetMonth() {
402 403
  CHECK_DATE(this);
  return LOCAL_MONTH(this);
404
}
405 406 407 408


// ECMA 262 - 15.9.5.13
function DateGetUTCMonth() {
409 410
  CHECK_DATE(this);
  return UTC_MONTH(this);
411
}
412 413 414 415


// ECMA 262 - 15.9.5.14
function DateGetDate() {
416 417
  CHECK_DATE(this);
  return LOCAL_DAY(this);
418
}
419 420 421 422


// ECMA 262 - 15.9.5.15
function DateGetUTCDate() {
423 424
  CHECK_DATE(this);
  return UTC_DAY(this);
425
}
426 427 428 429


// ECMA 262 - 15.9.5.16
function DateGetDay() {
430 431
  CHECK_DATE(this);
  return LOCAL_WEEKDAY(this);
432
}
433 434 435 436


// ECMA 262 - 15.9.5.17
function DateGetUTCDay() {
437 438
  CHECK_DATE(this);
  return UTC_WEEKDAY(this);
439
}
440 441 442 443


// ECMA 262 - 15.9.5.18
function DateGetHours() {
444 445
  CHECK_DATE(this);
  return LOCAL_HOUR(this);
446
}
447 448 449 450


// ECMA 262 - 15.9.5.19
function DateGetUTCHours() {
451 452
  CHECK_DATE(this);
  return UTC_HOUR(this);
453
}
454 455 456 457


// ECMA 262 - 15.9.5.20
function DateGetMinutes() {
458 459
  CHECK_DATE(this);
  return LOCAL_MIN(this);
460
}
461 462 463 464


// ECMA 262 - 15.9.5.21
function DateGetUTCMinutes() {
465 466
  CHECK_DATE(this);
  return UTC_MIN(this);
467
}
468 469 470 471


// ECMA 262 - 15.9.5.22
function DateGetSeconds() {
472 473
  CHECK_DATE(this);
  return LOCAL_SEC(this);
474
}
475 476 477 478


// ECMA 262 - 15.9.5.23
function DateGetUTCSeconds() {
479 480
  CHECK_DATE(this);
  return UTC_SEC(this)
481
}
482 483 484 485


// ECMA 262 - 15.9.5.24
function DateGetMilliseconds() {
486 487
  CHECK_DATE(this);
  return LOCAL_MS(this);
488
}
489 490 491 492


// ECMA 262 - 15.9.5.25
function DateGetUTCMilliseconds() {
493 494
  CHECK_DATE(this);
  return UTC_MS(this);
495
}
496 497 498 499


// ECMA 262 - 15.9.5.26
function DateGetTimezoneOffset() {
500 501
  CHECK_DATE(this);
  return TIMEZONE_OFFSET(this);
502
}
503 504 505 506


// ECMA 262 - 15.9.5.27
function DateSetTime(ms) {
507 508 509
  CHECK_DATE(this);
  SET_UTC_DATE_VALUE(this, ToNumber(ms));
  return UTC_DATE_VALUE(this);
510
}
511 512 513 514


// ECMA 262 - 15.9.5.28
function DateSetMilliseconds(ms) {
515 516
  CHECK_DATE(this);
  var t = LOCAL_DATE_VALUE(this);
517
  ms = ToNumber(ms);
518
  var time = MakeTime(LOCAL_HOUR(this), LOCAL_MIN(this), LOCAL_SEC(this), ms);
519
  return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
520
}
521 522 523 524


// ECMA 262 - 15.9.5.29
function DateSetUTCMilliseconds(ms) {
525 526
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
527
  ms = ToNumber(ms);
528 529 530
  var time = MakeTime(UTC_HOUR(this),
                      UTC_MIN(this),
                      UTC_SEC(this),
531
                      ms);
532
  return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
533
}
534 535 536 537


// ECMA 262 - 15.9.5.30
function DateSetSeconds(sec, ms) {
538 539
  CHECK_DATE(this);
  var t = LOCAL_DATE_VALUE(this);
540
  sec = ToNumber(sec);
541 542 543
  ms = %_ArgumentsLength() < 2 ? LOCAL_MS(this) : ToNumber(ms);
  var time = MakeTime(LOCAL_HOUR(this), LOCAL_MIN(this), sec, ms);
  return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
544
}
545 546 547 548


// ECMA 262 - 15.9.5.31
function DateSetUTCSeconds(sec, ms) {
549 550
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
551
  sec = ToNumber(sec);
552 553 554
  ms = %_ArgumentsLength() < 2 ? UTC_MS(this) : ToNumber(ms);
  var time = MakeTime(UTC_HOUR(this), UTC_MIN(this), sec, ms);
  return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
555
}
556 557 558 559


// ECMA 262 - 15.9.5.33
function DateSetMinutes(min, sec, ms) {
560 561
  CHECK_DATE(this);
  var t = LOCAL_DATE_VALUE(this);
562 563
  min = ToNumber(min);
  var argc = %_ArgumentsLength();
564 565 566 567
  sec = argc < 2 ? LOCAL_SEC(this) : ToNumber(sec);
  ms = argc < 3 ? LOCAL_MS(this) : ToNumber(ms);
  var time = MakeTime(LOCAL_HOUR(this), min, sec, ms);
  return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
568
}
569 570 571 572


// ECMA 262 - 15.9.5.34
function DateSetUTCMinutes(min, sec, ms) {
573 574
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
575 576
  min = ToNumber(min);
  var argc = %_ArgumentsLength();
577 578 579 580
  sec = argc < 2 ? UTC_SEC(this) : ToNumber(sec);
  ms = argc < 3 ? UTC_MS(this) : ToNumber(ms);
  var time = MakeTime(UTC_HOUR(this), min, sec, ms);
  return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
581
}
582 583 584 585


// ECMA 262 - 15.9.5.35
function DateSetHours(hour, min, sec, ms) {
586 587
  CHECK_DATE(this);
  var t = LOCAL_DATE_VALUE(this);
588 589
  hour = ToNumber(hour);
  var argc = %_ArgumentsLength();
590 591 592
  min = argc < 2 ? LOCAL_MIN(this) : ToNumber(min);
  sec = argc < 3 ? LOCAL_SEC(this) : ToNumber(sec);
  ms = argc < 4 ? LOCAL_MS(this) : ToNumber(ms);
593
  var time = MakeTime(hour, min, sec, ms);
594
  return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
595
}
596 597 598 599


// ECMA 262 - 15.9.5.34
function DateSetUTCHours(hour, min, sec, ms) {
600 601
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
602 603
  hour = ToNumber(hour);
  var argc = %_ArgumentsLength();
604 605 606
  min = argc < 2 ? UTC_MIN(this) : ToNumber(min);
  sec = argc < 3 ? UTC_SEC(this) : ToNumber(sec);
  ms = argc < 4 ? UTC_MS(this) : ToNumber(ms);
607
  var time = MakeTime(hour, min, sec, ms);
608
  return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
609
}
610 611 612 613


// ECMA 262 - 15.9.5.36
function DateSetDate(date) {
614 615
  CHECK_DATE(this);
  var t = LOCAL_DATE_VALUE(this);
616
  date = ToNumber(date);
617 618
  var day = MakeDay(LOCAL_YEAR(this), LOCAL_MONTH(this), date);
  return SET_LOCAL_DATE_VALUE(this, MakeDate(day, LOCAL_TIME_IN_DAY(this)));
619
}
620 621 622 623


// ECMA 262 - 15.9.5.37
function DateSetUTCDate(date) {
624 625
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
626
  date = ToNumber(date);
627 628
  var day = MakeDay(UTC_YEAR(this), UTC_MONTH(this), date);
  return SET_UTC_DATE_VALUE(this, MakeDate(day, UTC_TIME_IN_DAY(this)));
629
}
630 631 632 633


// ECMA 262 - 15.9.5.38
function DateSetMonth(month, date) {
634 635
  CHECK_DATE(this);
  var t = LOCAL_DATE_VALUE(this);
636
  month = ToNumber(month);
637 638 639
  date = %_ArgumentsLength() < 2 ? LOCAL_DAY(this) : ToNumber(date);
  var day = MakeDay(LOCAL_YEAR(this), month, date);
  return SET_LOCAL_DATE_VALUE(this, MakeDate(day, LOCAL_TIME_IN_DAY(this)));
640
}
641 642 643 644


// ECMA 262 - 15.9.5.39
function DateSetUTCMonth(month, date) {
645 646
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
647
  month = ToNumber(month);
648 649 650
  date = %_ArgumentsLength() < 2 ? UTC_DAY(this) : ToNumber(date);
  var day = MakeDay(UTC_YEAR(this), month, date);
  return SET_UTC_DATE_VALUE(this, MakeDate(day, UTC_TIME_IN_DAY(this)));
651
}
652 653 654 655


// ECMA 262 - 15.9.5.40
function DateSetFullYear(year, month, date) {
656 657
  CHECK_DATE(this);
  var t = LOCAL_DATE_VALUE(this);
658 659
  year = ToNumber(year);
  var argc = %_ArgumentsLength();
660 661 662 663 664 665 666 667 668 669
  var time ;
  if (NUMBER_IS_NAN(t)) {
    month = argc < 2 ? 0 : ToNumber(month);
    date = argc < 3 ? 1 : ToNumber(date);
    time = 0;
  } else {
    month = argc < 2 ? LOCAL_MONTH(this) : ToNumber(month);
    date = argc < 3 ? LOCAL_DAY(this) : ToNumber(date);
    time = LOCAL_TIME_IN_DAY(this);
  }
670
  var day = MakeDay(year, month, date);
671
  return SET_LOCAL_DATE_VALUE(this, MakeDate(day, time));
672
}
673 674 675 676


// ECMA 262 - 15.9.5.41
function DateSetUTCFullYear(year, month, date) {
677 678
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
679
  year = ToNumber(year);
680 681 682 683 684 685 686 687 688 689 690
  var argc = %_ArgumentsLength();
  var time ;
  if (NUMBER_IS_NAN(t)) {
    month = argc < 2 ? 0 : ToNumber(month);
    date = argc < 3 ? 1 : ToNumber(date);
    time = 0;
  } else {
    month = argc < 2 ? UTC_MONTH(this) : ToNumber(month);
    date = argc < 3 ? UTC_DAY(this) : ToNumber(date);
    time = UTC_TIME_IN_DAY(this);
  }
691
  var day = MakeDay(year, month, date);
692
  return SET_UTC_DATE_VALUE(this, MakeDate(day, time));
693
}
694 695 696 697


// ECMA 262 - 15.9.5.42
function DateToUTCString() {
698 699
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
700
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
701
  // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
702 703 704 705 706
  return WeekDays[UTC_WEEKDAY(this)] + ', '
      + TwoDigitString(UTC_DAY(this)) + ' '
      + Months[UTC_MONTH(this)] + ' '
      + UTC_YEAR(this) + ' '
      + TimeStringUTC(this) + ' GMT';
707
}
708 709 710 711


// ECMA 262 - B.2.4
function DateGetYear() {
712 713
  CHECK_DATE(this);
  return LOCAL_YEAR(this) - 1900;
714
}
715 716 717 718


// ECMA 262 - B.2.5
function DateSetYear(year) {
719
  CHECK_DATE(this);
720
  year = ToNumber(year);
721
  if (NUMBER_IS_NAN(year)) return SET_UTC_DATE_VALUE(this, $NaN);
722 723
  year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
      ? 1900 + TO_INTEGER(year) : year;
724 725 726 727 728 729 730 731 732 733 734 735 736
  var t = LOCAL_DATE_VALUE(this);
  var month, date, time;
  if (NUMBER_IS_NAN(t))  {
    month = 0;
    date = 1;
    time = 0;
  } else {
    month = LOCAL_MONTH(this);
    date = LOCAL_DAY(this);
    time = LOCAL_TIME_IN_DAY(this);
  }
  var day = MakeDay(year, month, date);
  return SET_LOCAL_DATE_VALUE(this, MakeDate(day, time));
737 738 739 740 741 742 743 744 745 746 747
}


// ECMA 262 - B.2.6
//
// Notice that this does not follow ECMA 262 completely.  ECMA 262
// says that toGMTString should be the same Function object as
// toUTCString.  JSC does not do this, so for compatibility we do not
// do that either.  Instead, we create a new function whose name
// property will return toGMTString.
function DateToGMTString() {
748
  return %_CallFunction(this, DateToUTCString);
749
}
750 751


752 753 754
function PadInt(n, digits) {
  if (digits == 1) return n;
  return n < MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
755 756 757
}


758
// ECMA 262 - 15.9.5.43
759
function DateToISOString() {
760 761
  CHECK_DATE(this);
  var t = UTC_DATE_VALUE(this);
762
  if (NUMBER_IS_NAN(t)) throw MakeRangeError("invalid_time_value", []);
763 764 765 766 767 768 769 770 771 772 773 774
  var year = this.getUTCFullYear();
  var year_string;
  if (year >= 0 && year <= 9999) {
    year_string = PadInt(year, 4);
  } else {
    if (year < 0) {
      year_string = "-" + PadInt(-year, 6);
    } else {
      year_string = "+" + PadInt(year, 6);
    }
  }
  return year_string +
775
      '-' + PadInt(this.getUTCMonth() + 1, 2) +
776
      '-' + PadInt(this.getUTCDate(), 2) +
777
      'T' + PadInt(this.getUTCHours(), 2) +
778
      ':' + PadInt(this.getUTCMinutes(), 2) +
779
      ':' + PadInt(this.getUTCSeconds(), 2) +
780
      '.' + PadInt(this.getUTCMilliseconds(), 3) +
781 782 783 784 785
      'Z';
}


function DateToJSON(key) {
786 787
  var o = ToObject(this);
  var tv = DefaultNumber(o);
788 789
  if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
    return null;
790 791
  }
  return o.toISOString();
792 793 794
}


795 796 797 798 799 800 801 802 803 804 805 806
function ResetDateCache() {
  // Reset the timezone cache:
  timezone_cache_time = $NaN;
  timezone_cache_timezone = undefined;

  // Reset the date cache:
  cache = Date_cache;
  cache.time = $NaN;
  cache.string = null;
}


807 808
// -------------------------------------------------------------------

809 810 811
function SetUpDate() {
  %CheckIsBootstrapping();
  // Set up non-enumerable properties of the Date object itself.
812 813 814 815 816 817
  InstallFunctions($Date, DONT_ENUM, $Array(
    "UTC", DateUTC,
    "parse", DateParse,
    "now", DateNow
  ));

818
  // Set up non-enumerable constructor property of the Date prototype object.
819
  %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
820

821
  // Set up non-enumerable functions of the Date prototype object and
822
  // set their names.
823
  InstallFunctions($Date.prototype, DONT_ENUM, $Array(
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
    "toString", DateToString,
    "toDateString", DateToDateString,
    "toTimeString", DateToTimeString,
    "toLocaleString", DateToLocaleString,
    "toLocaleDateString", DateToLocaleDateString,
    "toLocaleTimeString", DateToLocaleTimeString,
    "valueOf", DateValueOf,
    "getTime", DateGetTime,
    "getFullYear", DateGetFullYear,
    "getUTCFullYear", DateGetUTCFullYear,
    "getMonth", DateGetMonth,
    "getUTCMonth", DateGetUTCMonth,
    "getDate", DateGetDate,
    "getUTCDate", DateGetUTCDate,
    "getDay", DateGetDay,
    "getUTCDay", DateGetUTCDay,
    "getHours", DateGetHours,
    "getUTCHours", DateGetUTCHours,
    "getMinutes", DateGetMinutes,
    "getUTCMinutes", DateGetUTCMinutes,
    "getSeconds", DateGetSeconds,
    "getUTCSeconds", DateGetUTCSeconds,
    "getMilliseconds", DateGetMilliseconds,
    "getUTCMilliseconds", DateGetUTCMilliseconds,
    "getTimezoneOffset", DateGetTimezoneOffset,
    "setTime", DateSetTime,
    "setMilliseconds", DateSetMilliseconds,
    "setUTCMilliseconds", DateSetUTCMilliseconds,
    "setSeconds", DateSetSeconds,
    "setUTCSeconds", DateSetUTCSeconds,
    "setMinutes", DateSetMinutes,
    "setUTCMinutes", DateSetUTCMinutes,
    "setHours", DateSetHours,
    "setUTCHours", DateSetUTCHours,
    "setDate", DateSetDate,
    "setUTCDate", DateSetUTCDate,
    "setMonth", DateSetMonth,
    "setUTCMonth", DateSetUTCMonth,
    "setFullYear", DateSetFullYear,
    "setUTCFullYear", DateSetUTCFullYear,
    "toGMTString", DateToGMTString,
    "toUTCString", DateToUTCString,
    "getYear", DateGetYear,
867 868 869
    "setYear", DateSetYear,
    "toISOString", DateToISOString,
    "toJSON", DateToJSON
870 871
  ));
}
872

873
SetUpDate();