date.js 22.6 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
// 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.

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

32 33
var $Date = global.Date;

34 35 36 37
// -------------------------------------------------------------------

// This file contains date support implemented in JavaScript.

38 39 40 41 42
// Helper function to throw error.
function ThrowDateTypeError() {
  throw new $TypeError('this is not a Date object.');
}

43

44
var timezone_cache_time = NAN;
45 46
var timezone_cache_timezone;

47
function LocalTimezone(t) {
48
  if (NUMBER_IS_NAN(t)) return "";
49
  CheckDateCacheCurrent();
50
  if (t == timezone_cache_time) {
51 52
    return timezone_cache_timezone;
  }
53
  var timezone = %DateLocalTimezone(t);
54 55 56
  timezone_cache_time = t;
  timezone_cache_timezone = timezone;
  return timezone;
57
}
58 59 60


function UTC(time) {
61
  if (NUMBER_IS_NAN(time)) return time;
62 63
  // local_time_offset is needed before the call to DaylightSavingsOffset,
  // so it may be uninitialized.
64
  return %DateToUTC(time);
65
}
66 67 68 69


// ECMA 262 - 15.9.1.11
function MakeTime(hour, min, sec, ms) {
70 71 72 73
  if (!$isFinite(hour)) return NAN;
  if (!$isFinite(min)) return NAN;
  if (!$isFinite(sec)) return NAN;
  if (!$isFinite(ms)) return NAN;
74 75 76 77
  return TO_INTEGER(hour) * msPerHour
      + TO_INTEGER(min) * msPerMinute
      + TO_INTEGER(sec) * msPerSecond
      + TO_INTEGER(ms);
78
}
79 80 81 82 83


// ECMA 262 - 15.9.1.12
function TimeInYear(year) {
  return DaysInYear(year) * msPerDay;
84
}
85 86 87 88 89 90 91 92 93


// 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) {
94
  if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return NAN;
95

96 97 98 99
  // 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);
100

101
  if (year < kMinYear || year > kMaxYear ||
102
      month < kMinMonth || month > kMaxMonth) {
103
    return NAN;
104 105
  }

106
  // Now we rely on year and month being SMIs.
107
  return %DateMakeDay(year | 0, month | 0) + date - 1;
108
}
109 110 111 112


// ECMA 262 - 15.9.1.13
function MakeDate(day, time) {
113 114 115 116 117 118
  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.
119
  if ($abs(time) > MAX_TIME_BEFORE_UTC) return NAN;
120
  return time;
121
}
122 123 124 125


// ECMA 262 - 15.9.1.14
function TimeClip(time) {
126 127
  if (!$isFinite(time)) return NAN;
  if ($abs(time) > MAX_TIME_MS) return NAN;
128
  return TO_INTEGER(time);
129
}
130 131


132 133 134 135
// 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.
136
  time: 0,
137 138 139 140 141
  // String input for which the cached time is valid.
  string: null
};


142
function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
143 144 145 146 147 148 149 150 151 152
  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();
153
    SET_UTC_DATE_VALUE(this, value);
154 155
  } else if (argc == 1) {
    if (IS_NUMBER(year)) {
156
      value = year;
157 158 159
    } 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.
160
      CheckDateCacheCurrent();
161 162 163 164 165
      var cache = Date_cache;
      if (cache.string === year) {
        value = cache.time;
      } else {
        value = DateParse(year);
166 167 168 169
        if (!NUMBER_IS_NAN(value)) {
          cache.time = value;
          cache.string = year;
        }
170 171
      }

172
    } else {
173
      // According to ECMA 262, no hint should be given for this
174 175
      // conversion. However, ToPrimitive defaults to STRING_HINT for
      // Date objects which will lose precision when the Date
176
      // constructor is called with another Date object as its
177 178 179
      // 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.
180
      var time = ToPrimitive(year, NUMBER_HINT);
181
      value = IS_STRING(time) ? DateParse(time) : ToNumber(time);
182
    }
183
    SET_UTC_DATE_VALUE(this, value);
184
  } else {
185 186 187 188 189 190 191
    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;
192 193 194
    year = (!NUMBER_IS_NAN(year) &&
            0 <= TO_INTEGER(year) &&
            TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
195 196
    var day = MakeDay(year, month, date);
    var time = MakeTime(hours, minutes, seconds, ms);
197 198
    value = MakeDate(day, time);
    SET_LOCAL_DATE_VALUE(this, value);
199
  }
200
}
201 202 203


var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
204 205
var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
              'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
206 207 208 209


function TwoDigitString(value) {
  return value < 10 ? "0" + value : "" + value;
210
}
211 212


213 214 215 216 217
function DateString(date) {
  return WeekDays[LOCAL_WEEKDAY(date)] + ' '
      + Months[LOCAL_MONTH(date)] + ' '
      + TwoDigitString(LOCAL_DAY(date)) + ' '
      + LOCAL_YEAR(date);
218
}
219 220


221 222 223 224
var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
    'Thursday', 'Friday', 'Saturday'];
var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June',
    'July', 'August', 'September', 'October', 'November', 'December'];
225 226


227 228 229 230 231
function LongDateString(date) {
  return LongWeekDays[LOCAL_WEEKDAY(date)] + ', '
      + LongMonths[LOCAL_MONTH(date)] + ' '
      + TwoDigitString(LOCAL_DAY(date)) + ', '
      + LOCAL_YEAR(date);
232 233 234
}


235 236 237 238
function TimeString(date) {
  return TwoDigitString(LOCAL_HOUR(date)) + ':'
      + TwoDigitString(LOCAL_MIN(date)) + ':'
      + TwoDigitString(LOCAL_SEC(date));
239
}
240 241


242 243 244 245 246 247
function TimeStringUTC(date) {
  return TwoDigitString(UTC_HOUR(date)) + ':'
      + TwoDigitString(UTC_MIN(date)) + ':'
      + TwoDigitString(UTC_SEC(date));
}

248

249
function LocalTimezoneString(date) {
250 251
  var timezone = LocalTimezone(UTC_DATE_VALUE(date));

252
  var timezoneOffset = -TIMEZONE_OFFSET(date);
253
  var sign = (timezoneOffset >= 0) ? 1 : -1;
254 255
  var hours = FLOOR((sign * timezoneOffset)/60);
  var min   = FLOOR((sign * timezoneOffset)%60);
256 257
  var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
      TwoDigitString(hours) + TwoDigitString(min);
258
  return gmt + ' (' +  timezone + ')';
259
}
260 261


262 263
function DatePrintString(date) {
  return DateString(date) + ' ' + TimeString(date);
264
}
265 266 267

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

268
// Reused output buffer. Used when parsing date strings.
269
var parse_buffer = $Array(8);
270 271 272

// ECMA 262 - 15.9.4.2
function DateParse(string) {
273
  var arr = %DateParseString(ToString(string), parse_buffer);
274
  if (IS_NULL(arr)) return NAN;
275 276

  var day = MakeDay(arr[0], arr[1], arr[2]);
277
  var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
278
  var date = MakeDate(day, time);
279

280
  if (IS_NULL(arr[7])) {
281 282
    return TimeClip(UTC(date));
  } else {
283
    return TimeClip(date - arr[7] * 1000);
284
  }
285
}
286 287 288 289 290 291 292 293 294 295 296 297


// 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;
298 299 300
  year = (!NUMBER_IS_NAN(year) &&
          0 <= TO_INTEGER(year) &&
          TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
301 302
  var day = MakeDay(year, month, date);
  var time = MakeTime(hours, minutes, seconds, ms);
303
  return TimeClip(MakeDate(day, time));
304
}
305 306


307
// ECMA 262 - 15.9.4.4
308
function DateNow() {
309
  return %DateCurrentTime();
310
}
311 312 313 314


// ECMA 262 - 15.9.5.2
function DateToString() {
315
  var t = UTC_DATE_VALUE(this)
316
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
317 318
  var time_zone_string = LocalTimezoneString(this)
  return DatePrintString(this) + time_zone_string;
319
}
320 321 322 323


// ECMA 262 - 15.9.5.3
function DateToDateString() {
324
  var t = UTC_DATE_VALUE(this);
325
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
326
  return DateString(this);
327
}
328 329 330 331


// ECMA 262 - 15.9.5.4
function DateToTimeString() {
332
  var t = UTC_DATE_VALUE(this);
333
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
334 335
  var time_zone_string = LocalTimezoneString(this);
  return TimeString(this) + time_zone_string;
336 337 338 339 340
}


// ECMA 262 - 15.9.5.5
function DateToLocaleString() {
341
  return %_CallFunction(this, DateToString);
342 343 344 345 346
}


// ECMA 262 - 15.9.5.6
function DateToLocaleDateString() {
347
  var t = UTC_DATE_VALUE(this);
348
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
349
  return LongDateString(this);
350
}
351 352


353 354
// ECMA 262 - 15.9.5.7
function DateToLocaleTimeString() {
355
  var t = UTC_DATE_VALUE(this);
356
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
357
  return TimeString(this);
358 359 360 361 362
}


// ECMA 262 - 15.9.5.8
function DateValueOf() {
363
  return UTC_DATE_VALUE(this);
364
}
365 366


367 368
// ECMA 262 - 15.9.5.9
function DateGetTime() {
369
  return UTC_DATE_VALUE(this);
370 371 372 373 374
}


// ECMA 262 - 15.9.5.10
function DateGetFullYear() {
375
  return LOCAL_YEAR(this);
376
}
377 378 379 380


// ECMA 262 - 15.9.5.11
function DateGetUTCFullYear() {
381
  return UTC_YEAR(this);
382
}
383 384 385 386


// ECMA 262 - 15.9.5.12
function DateGetMonth() {
387
  return LOCAL_MONTH(this);
388
}
389 390 391 392


// ECMA 262 - 15.9.5.13
function DateGetUTCMonth() {
393
  return UTC_MONTH(this);
394
}
395 396 397 398


// ECMA 262 - 15.9.5.14
function DateGetDate() {
399
  return LOCAL_DAY(this);
400
}
401 402 403 404


// ECMA 262 - 15.9.5.15
function DateGetUTCDate() {
405
  return UTC_DAY(this);
406
}
407 408 409 410


// ECMA 262 - 15.9.5.16
function DateGetDay() {
411
  return LOCAL_WEEKDAY(this);
412
}
413 414 415 416


// ECMA 262 - 15.9.5.17
function DateGetUTCDay() {
417
  return UTC_WEEKDAY(this);
418
}
419 420 421 422


// ECMA 262 - 15.9.5.18
function DateGetHours() {
423
  return LOCAL_HOUR(this);
424
}
425 426 427 428


// ECMA 262 - 15.9.5.19
function DateGetUTCHours() {
429
  return UTC_HOUR(this);
430
}
431 432 433 434


// ECMA 262 - 15.9.5.20
function DateGetMinutes() {
435
  return LOCAL_MIN(this);
436
}
437 438 439 440


// ECMA 262 - 15.9.5.21
function DateGetUTCMinutes() {
441
  return UTC_MIN(this);
442
}
443 444 445 446


// ECMA 262 - 15.9.5.22
function DateGetSeconds() {
447
  return LOCAL_SEC(this);
448
}
449 450 451 452


// ECMA 262 - 15.9.5.23
function DateGetUTCSeconds() {
453
  return UTC_SEC(this)
454
}
455 456 457 458


// ECMA 262 - 15.9.5.24
function DateGetMilliseconds() {
459
  return LOCAL_MS(this);
460
}
461 462 463 464


// ECMA 262 - 15.9.5.25
function DateGetUTCMilliseconds() {
465
  return UTC_MS(this);
466
}
467 468 469 470


// ECMA 262 - 15.9.5.26
function DateGetTimezoneOffset() {
471
  return TIMEZONE_OFFSET(this);
472
}
473 474 475 476


// ECMA 262 - 15.9.5.27
function DateSetTime(ms) {
477 478 479
  CHECK_DATE(this);
  SET_UTC_DATE_VALUE(this, ToNumber(ms));
  return UTC_DATE_VALUE(this);
480
}
481 482 483 484


// ECMA 262 - 15.9.5.28
function DateSetMilliseconds(ms) {
485
  var t = LOCAL_DATE_VALUE(this);
486
  ms = ToNumber(ms);
487
  var time = MakeTime(LOCAL_HOUR(this), LOCAL_MIN(this), LOCAL_SEC(this), ms);
488
  return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
489
}
490 491 492 493


// ECMA 262 - 15.9.5.29
function DateSetUTCMilliseconds(ms) {
494
  var t = UTC_DATE_VALUE(this);
495
  ms = ToNumber(ms);
496 497 498
  var time = MakeTime(UTC_HOUR(this),
                      UTC_MIN(this),
                      UTC_SEC(this),
499
                      ms);
500
  return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
501
}
502 503 504 505


// ECMA 262 - 15.9.5.30
function DateSetSeconds(sec, ms) {
506
  var t = LOCAL_DATE_VALUE(this);
507
  sec = ToNumber(sec);
508 509 510
  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));
511
}
512 513 514 515


// ECMA 262 - 15.9.5.31
function DateSetUTCSeconds(sec, ms) {
516
  var t = UTC_DATE_VALUE(this);
517
  sec = ToNumber(sec);
518 519 520
  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));
521
}
522 523 524 525


// ECMA 262 - 15.9.5.33
function DateSetMinutes(min, sec, ms) {
526
  var t = LOCAL_DATE_VALUE(this);
527 528
  min = ToNumber(min);
  var argc = %_ArgumentsLength();
529 530 531 532
  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));
533
}
534 535 536 537


// ECMA 262 - 15.9.5.34
function DateSetUTCMinutes(min, sec, ms) {
538
  var t = UTC_DATE_VALUE(this);
539 540
  min = ToNumber(min);
  var argc = %_ArgumentsLength();
541 542 543 544
  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));
545
}
546 547 548 549


// ECMA 262 - 15.9.5.35
function DateSetHours(hour, min, sec, ms) {
550
  var t = LOCAL_DATE_VALUE(this);
551 552
  hour = ToNumber(hour);
  var argc = %_ArgumentsLength();
553 554 555
  min = argc < 2 ? LOCAL_MIN(this) : ToNumber(min);
  sec = argc < 3 ? LOCAL_SEC(this) : ToNumber(sec);
  ms = argc < 4 ? LOCAL_MS(this) : ToNumber(ms);
556
  var time = MakeTime(hour, min, sec, ms);
557
  return SET_LOCAL_DATE_VALUE(this, MakeDate(LOCAL_DAYS(this), time));
558
}
559 560 561 562


// ECMA 262 - 15.9.5.34
function DateSetUTCHours(hour, min, sec, ms) {
563
  var t = UTC_DATE_VALUE(this);
564 565
  hour = ToNumber(hour);
  var argc = %_ArgumentsLength();
566 567 568
  min = argc < 2 ? UTC_MIN(this) : ToNumber(min);
  sec = argc < 3 ? UTC_SEC(this) : ToNumber(sec);
  ms = argc < 4 ? UTC_MS(this) : ToNumber(ms);
569
  var time = MakeTime(hour, min, sec, ms);
570
  return SET_UTC_DATE_VALUE(this, MakeDate(UTC_DAYS(this), time));
571
}
572 573 574 575


// ECMA 262 - 15.9.5.36
function DateSetDate(date) {
576
  var t = LOCAL_DATE_VALUE(this);
577
  date = ToNumber(date);
578 579
  var day = MakeDay(LOCAL_YEAR(this), LOCAL_MONTH(this), date);
  return SET_LOCAL_DATE_VALUE(this, MakeDate(day, LOCAL_TIME_IN_DAY(this)));
580
}
581 582 583 584


// ECMA 262 - 15.9.5.37
function DateSetUTCDate(date) {
585
  var t = UTC_DATE_VALUE(this);
586
  date = ToNumber(date);
587 588
  var day = MakeDay(UTC_YEAR(this), UTC_MONTH(this), date);
  return SET_UTC_DATE_VALUE(this, MakeDate(day, UTC_TIME_IN_DAY(this)));
589
}
590 591 592 593


// ECMA 262 - 15.9.5.38
function DateSetMonth(month, date) {
594
  var t = LOCAL_DATE_VALUE(this);
595
  month = ToNumber(month);
596 597 598
  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)));
599
}
600 601 602 603


// ECMA 262 - 15.9.5.39
function DateSetUTCMonth(month, date) {
604
  var t = UTC_DATE_VALUE(this);
605
  month = ToNumber(month);
606 607 608
  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)));
609
}
610 611 612 613


// ECMA 262 - 15.9.5.40
function DateSetFullYear(year, month, date) {
614
  var t = LOCAL_DATE_VALUE(this);
615 616
  year = ToNumber(year);
  var argc = %_ArgumentsLength();
617 618 619 620 621 622 623 624 625 626
  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);
  }
627
  var day = MakeDay(year, month, date);
628
  return SET_LOCAL_DATE_VALUE(this, MakeDate(day, time));
629
}
630 631 632 633


// ECMA 262 - 15.9.5.41
function DateSetUTCFullYear(year, month, date) {
634
  var t = UTC_DATE_VALUE(this);
635
  year = ToNumber(year);
636 637 638 639 640 641 642 643 644 645 646
  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);
  }
647
  var day = MakeDay(year, month, date);
648
  return SET_UTC_DATE_VALUE(this, MakeDate(day, time));
649
}
650 651 652 653


// ECMA 262 - 15.9.5.42
function DateToUTCString() {
654
  var t = UTC_DATE_VALUE(this);
655
  if (NUMBER_IS_NAN(t)) return kInvalidDate;
656
  // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
657 658 659 660 661
  return WeekDays[UTC_WEEKDAY(this)] + ', '
      + TwoDigitString(UTC_DAY(this)) + ' '
      + Months[UTC_MONTH(this)] + ' '
      + UTC_YEAR(this) + ' '
      + TimeStringUTC(this) + ' GMT';
662
}
663 664 665 666


// ECMA 262 - B.2.4
function DateGetYear() {
667
  return LOCAL_YEAR(this) - 1900;
668
}
669 670 671 672


// ECMA 262 - B.2.5
function DateSetYear(year) {
673
  CHECK_DATE(this);
674
  year = ToNumber(year);
675
  if (NUMBER_IS_NAN(year)) return SET_UTC_DATE_VALUE(this, NAN);
676 677
  year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
      ? 1900 + TO_INTEGER(year) : year;
678 679 680 681 682 683 684 685 686 687 688 689 690
  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));
691 692 693 694 695 696 697 698 699 700 701
}


// 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() {
702
  return %_CallFunction(this, DateToUTCString);
703
}
704 705


706 707 708
function PadInt(n, digits) {
  if (digits == 1) return n;
  return n < MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
709 710 711
}


712
// ECMA 262 - 15.9.5.43
713
function DateToISOString() {
714
  var t = UTC_DATE_VALUE(this);
715
  if (NUMBER_IS_NAN(t)) throw MakeRangeError("invalid_time_value", []);
716 717 718 719 720 721 722 723 724 725 726 727
  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 +
728
      '-' + PadInt(this.getUTCMonth() + 1, 2) +
729
      '-' + PadInt(this.getUTCDate(), 2) +
730
      'T' + PadInt(this.getUTCHours(), 2) +
731
      ':' + PadInt(this.getUTCMinutes(), 2) +
732
      ':' + PadInt(this.getUTCSeconds(), 2) +
733
      '.' + PadInt(this.getUTCMilliseconds(), 3) +
734 735 736 737 738
      'Z';
}


function DateToJSON(key) {
739 740
  var o = ToObject(this);
  var tv = DefaultNumber(o);
741 742
  if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
    return null;
743 744
  }
  return o.toISOString();
745 746 747
}


748 749 750 751 752 753 754 755 756 757 758 759 760
var date_cache_version_holder;
var date_cache_version = NAN;


function CheckDateCacheCurrent() {
  if (!date_cache_version_holder) {
    date_cache_version_holder = %DateCacheVersion();
  }
  if (date_cache_version_holder[0] == date_cache_version) {
    return;
  }
  date_cache_version = date_cache_version_holder[0];

761
  // Reset the timezone cache:
762
  timezone_cache_time = NAN;
763
  timezone_cache_timezone = UNDEFINED;
764 765

  // Reset the date cache:
766 767
  Date_cache.time = NAN;
  Date_cache.string = null;
768 769 770
}


771 772
// -------------------------------------------------------------------

773 774
function SetUpDate() {
  %CheckIsBootstrapping();
775 776

  %SetCode($Date, DateConstructor);
777
  %FunctionSetPrototype($Date, new $Date(NAN));
778

779
  // Set up non-enumerable properties of the Date object itself.
780 781 782 783 784 785
  InstallFunctions($Date, DONT_ENUM, $Array(
    "UTC", DateUTC,
    "parse", DateParse,
    "now", DateNow
  ));

786
  // Set up non-enumerable constructor property of the Date prototype object.
787
  %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
788

789
  // Set up non-enumerable functions of the Date prototype object and
790
  // set their names.
791
  InstallFunctions($Date.prototype, DONT_ENUM, $Array(
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
    "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,
835 836 837
    "setYear", DateSetYear,
    "toISOString", DateToISOString,
    "toJSON", DateToJSON
838 839
  ));
}
840

841
SetUpDate();