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