blob: ccefce57638812366eb32776b5cbdc6c1d79ebaf [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +00001// 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:
Ben Murdoch85b71792012-04-11 18:30:58 +010031// const $isFinite = GlobalIsFinite;
Andrei Popescu31002712010-02-23 13:46:05 +000032
33// -------------------------------------------------------------------
34
35// This file contains date support implemented in JavaScript.
36
Ben Murdoch85b71792012-04-11 18:30:58 +010037
Andrei Popescu31002712010-02-23 13:46:05 +000038// Keep reference to original values of some global properties. This
39// has the added benefit that the code in this file is isolated from
40// changes to these properties.
Ben Murdoch85b71792012-04-11 18:30:58 +010041const $Date = global.Date;
Andrei Popescu31002712010-02-23 13:46:05 +000042
43// Helper function to throw error.
44function ThrowDateTypeError() {
45 throw new $TypeError('this is not a Date object.');
46}
47
Ben Murdoch85b71792012-04-11 18:30:58 +010048// ECMA 262 - 5.2
49function Modulo(value, remainder) {
50 var mod = value % remainder;
51 // Guard against returning -0.
52 if (mod == 0) return 0;
53 return mod >= 0 ? mod : mod + remainder;
54}
55
56
57function TimeWithinDay(time) {
58 return Modulo(time, msPerDay);
59}
60
61
62// ECMA 262 - 15.9.1.3
63function DaysInYear(year) {
64 if (year % 4 != 0) return 365;
65 if ((year % 100 == 0) && (year % 400 != 0)) return 365;
66 return 366;
67}
68
69
70function DayFromYear(year) {
71 return 365 * (year-1970)
72 + FLOOR((year-1969)/4)
73 - FLOOR((year-1901)/100)
74 + FLOOR((year-1601)/400);
75}
76
77
78function TimeFromYear(year) {
79 return msPerDay * DayFromYear(year);
80}
81
82
83function InLeapYear(time) {
84 return DaysInYear(YearFromTime(time)) - 365; // Returns 1 or 0.
85}
86
87
88// ECMA 262 - 15.9.1.9
89function EquivalentYear(year) {
90 // Returns an equivalent year in the range [2008-2035] matching
91 // - leap year.
92 // - week day of first day.
93 var time = TimeFromYear(year);
94 var recent_year = (InLeapYear(time) == 0 ? 1967 : 1956) +
95 (WeekDay(time) * 12) % 28;
96 // Find the year in the range 2008..2037 that is equivalent mod 28.
97 // Add 3*28 to give a positive argument to the modulus operator.
98 return 2008 + (recent_year + 3*28 - 2008) % 28;
99}
100
101
102function EquivalentTime(t) {
103 // The issue here is that some library calls don't work right for dates
104 // that cannot be represented using a non-negative signed 32 bit integer
105 // (measured in whole seconds based on the 1970 epoch).
106 // We solve this by mapping the time to a year with same leap-year-ness
107 // and same starting day for the year. The ECMAscript specification says
108 // we must do this, but for compatibility with other browsers, we use
109 // the actual year if it is in the range 1970..2037
110 if (t >= 0 && t <= 2.1e12) return t;
111
112 var day = MakeDay(EquivalentYear(YearFromTime(t)),
113 MonthFromTime(t),
114 DateFromTime(t));
115 return MakeDate(day, TimeWithinDay(t));
116}
117
118
119// local_time_offset is initialized when the DST_offset_cache is missed.
120// It must not be used until after a call to DaylightSavingsOffset().
121// In this way, only one check, for a DST cache miss, is needed.
122var local_time_offset;
123
124
125// Because computing the DST offset is an expensive operation,
126// we keep a cache of the last computed DST offset along with a time interval
127// where we know the cache is valid.
128// When the cache is valid, local_time_offset is also valid.
129var DST_offset_cache = {
130 // Cached DST offset.
131 offset: 0,
132 // Time interval where the cached offset is valid.
133 start: 0, end: -1,
134 // Size of next interval expansion.
135 increment: 0,
136 initial_increment: 19 * msPerDay
137};
138
139
140// NOTE: The implementation relies on the fact that no time zones have
141// more than one daylight savings offset change per 19 days.
142//
143// In Egypt in 2010 they decided to suspend DST during Ramadan. This
144// led to a short interval where DST is in effect from September 10 to
145// September 30.
146//
147// If this function is called with NaN it returns NaN.
148function DaylightSavingsOffset(t) {
149 // Load the cache object from the builtins object.
150 var cache = DST_offset_cache;
151
152 // Cache the start and the end in local variables for fast access.
153 var start = cache.start;
154 var end = cache.end;
155
156 if (start <= t) {
157 // If the time fits in the cached interval, return the cached offset.
158 if (t <= end) return cache.offset;
159
160 // If the cache misses, the local_time_offset may not be initialized.
161 if (IS_UNDEFINED(local_time_offset)) {
162 local_time_offset = %DateLocalTimeOffset();
163 }
164
165 // Compute a possible new interval end.
166 var new_end = end + cache.increment;
167
168 if (t <= new_end) {
169 var end_offset = %DateDaylightSavingsOffset(EquivalentTime(new_end));
170 if (cache.offset == end_offset) {
171 // If the offset at the end of the new interval still matches
172 // the offset in the cache, we grow the cached time interval
173 // and return the offset.
174 cache.end = new_end;
175 cache.increment = cache.initial_increment;
176 return end_offset;
177 } else {
178 var offset = %DateDaylightSavingsOffset(EquivalentTime(t));
179 if (offset == end_offset) {
180 // The offset at the given time is equal to the offset at the
181 // new end of the interval, so that means that we've just skipped
182 // the point in time where the DST offset change occurred. Updated
183 // the interval to reflect this and reset the increment.
184 cache.start = t;
185 cache.end = new_end;
186 cache.increment = cache.initial_increment;
187 } else {
188 // The interval contains a DST offset change and the given time is
189 // before it. Adjust the increment to avoid a linear search for
190 // the offset change point and change the end of the interval.
191 cache.increment /= 3;
192 cache.end = t;
193 }
194 // Update the offset in the cache and return it.
195 cache.offset = offset;
196 return offset;
197 }
198 }
199 }
200
201 // If the cache misses, the local_time_offset may not be initialized.
202 if (IS_UNDEFINED(local_time_offset)) {
203 local_time_offset = %DateLocalTimeOffset();
204 }
205 // Compute the DST offset for the time and shrink the cache interval
206 // to only contain the time. This allows fast repeated DST offset
207 // computations for the same time.
208 var offset = %DateDaylightSavingsOffset(EquivalentTime(t));
209 cache.offset = offset;
210 cache.start = cache.end = t;
211 cache.increment = cache.initial_increment;
212 return offset;
213}
214
Andrei Popescu31002712010-02-23 13:46:05 +0000215
216var timezone_cache_time = $NaN;
217var timezone_cache_timezone;
218
219function LocalTimezone(t) {
220 if (NUMBER_IS_NAN(t)) return "";
221 if (t == timezone_cache_time) {
222 return timezone_cache_timezone;
223 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100224 var timezone = %DateLocalTimezone(EquivalentTime(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000225 timezone_cache_time = t;
226 timezone_cache_timezone = timezone;
227 return timezone;
228}
229
230
Ben Murdoch85b71792012-04-11 18:30:58 +0100231function WeekDay(time) {
232 return Modulo(DAY(time) + 4, 7);
233}
234
235
236function LocalTime(time) {
237 if (NUMBER_IS_NAN(time)) return time;
238 // DaylightSavingsOffset called before local_time_offset used.
239 return time + DaylightSavingsOffset(time) + local_time_offset;
240}
241
242
243var ltcache = {
244 key: null,
245 val: null
246};
247
248function LocalTimeNoCheck(time) {
249 var ltc = ltcache;
250 if (%_ObjectEquals(time, ltc.key)) return ltc.val;
251
252 // Inline the DST offset cache checks for speed.
253 // The cache is hit, or DaylightSavingsOffset is called,
254 // before local_time_offset is used.
255 var cache = DST_offset_cache;
256 if (cache.start <= time && time <= cache.end) {
257 var dst_offset = cache.offset;
258 } else {
259 var dst_offset = DaylightSavingsOffset(time);
260 }
261 ltc.key = time;
262 return (ltc.val = time + local_time_offset + dst_offset);
263}
264
265
Andrei Popescu31002712010-02-23 13:46:05 +0000266function UTC(time) {
267 if (NUMBER_IS_NAN(time)) return time;
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100268 // local_time_offset is needed before the call to DaylightSavingsOffset,
269 // so it may be uninitialized.
Ben Murdoch85b71792012-04-11 18:30:58 +0100270 if (IS_UNDEFINED(local_time_offset)) {
271 local_time_offset = %DateLocalTimeOffset();
272 }
273 var tmp = time - local_time_offset;
274 return tmp - DaylightSavingsOffset(tmp);
Andrei Popescu31002712010-02-23 13:46:05 +0000275}
276
277
278// ECMA 262 - 15.9.1.11
279function MakeTime(hour, min, sec, ms) {
280 if (!$isFinite(hour)) return $NaN;
281 if (!$isFinite(min)) return $NaN;
282 if (!$isFinite(sec)) return $NaN;
283 if (!$isFinite(ms)) return $NaN;
284 return TO_INTEGER(hour) * msPerHour
285 + TO_INTEGER(min) * msPerMinute
286 + TO_INTEGER(sec) * msPerSecond
287 + TO_INTEGER(ms);
288}
289
290
291// ECMA 262 - 15.9.1.12
292function TimeInYear(year) {
293 return DaysInYear(year) * msPerDay;
294}
295
296
Ben Murdoch85b71792012-04-11 18:30:58 +0100297var ymd_from_time_cache = [$NaN, $NaN, $NaN];
298var ymd_from_time_cached_time = $NaN;
299
300function YearFromTime(t) {
301 if (t !== ymd_from_time_cached_time) {
302 if (!$isFinite(t)) {
303 return $NaN;
304 }
305
306 %DateYMDFromTime(t, ymd_from_time_cache);
307 ymd_from_time_cached_time = t
308 }
309
310 return ymd_from_time_cache[0];
311}
312
313function MonthFromTime(t) {
314 if (t !== ymd_from_time_cached_time) {
315 if (!$isFinite(t)) {
316 return $NaN;
317 }
318 %DateYMDFromTime(t, ymd_from_time_cache);
319 ymd_from_time_cached_time = t
320 }
321
322 return ymd_from_time_cache[1];
323}
324
325function DateFromTime(t) {
326 if (t !== ymd_from_time_cached_time) {
327 if (!$isFinite(t)) {
328 return $NaN;
329 }
330
331 %DateYMDFromTime(t, ymd_from_time_cache);
332 ymd_from_time_cached_time = t
333 }
334
335 return ymd_from_time_cache[2];
336}
337
338
Andrei Popescu31002712010-02-23 13:46:05 +0000339// Compute number of days given a year, month, date.
340// Note that month and date can lie outside the normal range.
341// For example:
342// MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
343// MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
344// MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
345function MakeDay(year, month, date) {
346 if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return $NaN;
347
Steve Block8defd9f2010-07-08 12:39:36 +0100348 // Convert to integer and map -0 to 0.
349 year = TO_INTEGER_MAP_MINUS_ZERO(year);
350 month = TO_INTEGER_MAP_MINUS_ZERO(month);
351 date = TO_INTEGER_MAP_MINUS_ZERO(date);
Andrei Popescu31002712010-02-23 13:46:05 +0000352
Steve Block6ded16b2010-05-10 14:33:55 +0100353 if (year < kMinYear || year > kMaxYear ||
Ben Murdoch85b71792012-04-11 18:30:58 +0100354 month < kMinMonth || month > kMaxMonth ||
355 date < kMinDate || date > kMaxDate) {
Steve Block6ded16b2010-05-10 14:33:55 +0100356 return $NaN;
Andrei Popescu31002712010-02-23 13:46:05 +0000357 }
358
Ben Murdoch85b71792012-04-11 18:30:58 +0100359 // Now we rely on year, month and date being SMIs.
360 return %DateMakeDay(year, month, date);
Andrei Popescu31002712010-02-23 13:46:05 +0000361}
362
363
364// ECMA 262 - 15.9.1.13
365function MakeDate(day, time) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100366 var time = day * msPerDay + time;
367 // Some of our runtime funtions for computing UTC(time) rely on
368 // times not being significantly larger than MAX_TIME_MS. If there
369 // is no way that the time can be within range even after UTC
370 // conversion we return NaN immediately instead of relying on
371 // TimeClip to do it.
372 if ($abs(time) > MAX_TIME_BEFORE_UTC) return $NaN;
373 return time;
Andrei Popescu31002712010-02-23 13:46:05 +0000374}
375
376
377// ECMA 262 - 15.9.1.14
378function TimeClip(time) {
379 if (!$isFinite(time)) return $NaN;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100380 if ($abs(time) > MAX_TIME_MS) return $NaN;
Andrei Popescu31002712010-02-23 13:46:05 +0000381 return TO_INTEGER(time);
382}
383
384
385// The Date cache is used to limit the cost of parsing the same Date
386// strings over and over again.
387var Date_cache = {
388 // Cached time value.
389 time: $NaN,
Ben Murdoch85b71792012-04-11 18:30:58 +0100390 // Cached year when interpreting the time as a local time. Only
391 // valid when the time matches cached time.
392 year: $NaN,
Andrei Popescu31002712010-02-23 13:46:05 +0000393 // String input for which the cached time is valid.
394 string: null
395};
396
397
398%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
399 if (!%_IsConstructCall()) {
400 // ECMA 262 - 15.9.2
401 return (new $Date()).toString();
402 }
403
404 // ECMA 262 - 15.9.3
405 var argc = %_ArgumentsLength();
406 var value;
407 if (argc == 0) {
408 value = %DateCurrentTime();
Ben Murdoch85b71792012-04-11 18:30:58 +0100409
Andrei Popescu31002712010-02-23 13:46:05 +0000410 } else if (argc == 1) {
411 if (IS_NUMBER(year)) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100412 value = TimeClip(year);
413
Andrei Popescu31002712010-02-23 13:46:05 +0000414 } else if (IS_STRING(year)) {
415 // Probe the Date cache. If we already have a time value for the
416 // given time, we re-use that instead of parsing the string again.
417 var cache = Date_cache;
418 if (cache.string === year) {
419 value = cache.time;
420 } else {
421 value = DateParse(year);
422 if (!NUMBER_IS_NAN(value)) {
423 cache.time = value;
Ben Murdoch85b71792012-04-11 18:30:58 +0100424 cache.year = YearFromTime(LocalTimeNoCheck(value));
Andrei Popescu31002712010-02-23 13:46:05 +0000425 cache.string = year;
426 }
427 }
428
429 } else {
430 // According to ECMA 262, no hint should be given for this
431 // conversion. However, ToPrimitive defaults to STRING_HINT for
432 // Date objects which will lose precision when the Date
433 // constructor is called with another Date object as its
434 // argument. We therefore use NUMBER_HINT for the conversion,
435 // which is the default for everything else than Date objects.
436 // This makes us behave like KJS and SpiderMonkey.
437 var time = ToPrimitive(year, NUMBER_HINT);
Ben Murdoch85b71792012-04-11 18:30:58 +0100438 value = IS_STRING(time) ? DateParse(time) : TimeClip(ToNumber(time));
Andrei Popescu31002712010-02-23 13:46:05 +0000439 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100440
Andrei Popescu31002712010-02-23 13:46:05 +0000441 } else {
442 year = ToNumber(year);
443 month = ToNumber(month);
444 date = argc > 2 ? ToNumber(date) : 1;
445 hours = argc > 3 ? ToNumber(hours) : 0;
446 minutes = argc > 4 ? ToNumber(minutes) : 0;
447 seconds = argc > 5 ? ToNumber(seconds) : 0;
448 ms = argc > 6 ? ToNumber(ms) : 0;
Ben Murdoch85b71792012-04-11 18:30:58 +0100449 year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
450 ? 1900 + TO_INTEGER(year) : year;
Andrei Popescu31002712010-02-23 13:46:05 +0000451 var day = MakeDay(year, month, date);
452 var time = MakeTime(hours, minutes, seconds, ms);
Ben Murdoch85b71792012-04-11 18:30:58 +0100453 value = TimeClip(UTC(MakeDate(day, time)));
Andrei Popescu31002712010-02-23 13:46:05 +0000454 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100455 %_SetValueOf(this, value);
Andrei Popescu31002712010-02-23 13:46:05 +0000456});
457
458
Andrei Popescu31002712010-02-23 13:46:05 +0000459%FunctionSetPrototype($Date, new $Date($NaN));
460
461
462var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
Ben Murdoch85b71792012-04-11 18:30:58 +0100463var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
Andrei Popescu31002712010-02-23 13:46:05 +0000464
465
466function TwoDigitString(value) {
467 return value < 10 ? "0" + value : "" + value;
468}
469
470
Ben Murdoch85b71792012-04-11 18:30:58 +0100471function DateString(time) {
472 return WeekDays[WeekDay(time)] + ' '
473 + Months[MonthFromTime(time)] + ' '
474 + TwoDigitString(DateFromTime(time)) + ' '
475 + YearFromTime(time);
Andrei Popescu31002712010-02-23 13:46:05 +0000476}
477
478
Ben Murdoch85b71792012-04-11 18:30:58 +0100479var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
480var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
Andrei Popescu31002712010-02-23 13:46:05 +0000481
482
Ben Murdoch85b71792012-04-11 18:30:58 +0100483function LongDateString(time) {
484 return LongWeekDays[WeekDay(time)] + ', '
485 + LongMonths[MonthFromTime(time)] + ' '
486 + TwoDigitString(DateFromTime(time)) + ', '
487 + YearFromTime(time);
Andrei Popescu31002712010-02-23 13:46:05 +0000488}
489
490
Ben Murdoch85b71792012-04-11 18:30:58 +0100491function TimeString(time) {
492 return TwoDigitString(HOUR_FROM_TIME(time)) + ':'
493 + TwoDigitString(MIN_FROM_TIME(time)) + ':'
494 + TwoDigitString(SEC_FROM_TIME(time));
Andrei Popescu31002712010-02-23 13:46:05 +0000495}
496
497
Ben Murdoch85b71792012-04-11 18:30:58 +0100498function LocalTimezoneString(time) {
499 var old_timezone = timezone_cache_timezone;
500 var timezone = LocalTimezone(time);
501 if (old_timezone && timezone != old_timezone) {
502 // If the timezone string has changed from the one that we cached,
503 // the local time offset may now be wrong. So we need to update it
504 // and try again.
505 local_time_offset = %DateLocalTimeOffset();
506 // We also need to invalidate the DST cache as the new timezone may have
507 // different DST times.
508 var dst_cache = DST_offset_cache;
509 dst_cache.start = 0;
510 dst_cache.end = -1;
511 }
Ben Murdochd69d2e32010-03-30 12:55:27 +0100512
Ben Murdoch85b71792012-04-11 18:30:58 +0100513 var timezoneOffset =
514 (DaylightSavingsOffset(time) + local_time_offset) / msPerMinute;
Andrei Popescu31002712010-02-23 13:46:05 +0000515 var sign = (timezoneOffset >= 0) ? 1 : -1;
516 var hours = FLOOR((sign * timezoneOffset)/60);
517 var min = FLOOR((sign * timezoneOffset)%60);
518 var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
519 TwoDigitString(hours) + TwoDigitString(min);
Ben Murdochd69d2e32010-03-30 12:55:27 +0100520 return gmt + ' (' + timezone + ')';
Andrei Popescu31002712010-02-23 13:46:05 +0000521}
522
523
Ben Murdoch85b71792012-04-11 18:30:58 +0100524function DatePrintString(time) {
525 return DateString(time) + ' ' + TimeString(time);
Andrei Popescu31002712010-02-23 13:46:05 +0000526}
527
528// -------------------------------------------------------------------
529
530// Reused output buffer. Used when parsing date strings.
Steve Block6ded16b2010-05-10 14:33:55 +0100531var parse_buffer = $Array(8);
Andrei Popescu31002712010-02-23 13:46:05 +0000532
533// ECMA 262 - 15.9.4.2
534function DateParse(string) {
535 var arr = %DateParseString(ToString(string), parse_buffer);
536 if (IS_NULL(arr)) return $NaN;
537
538 var day = MakeDay(arr[0], arr[1], arr[2]);
Steve Block6ded16b2010-05-10 14:33:55 +0100539 var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
Andrei Popescu31002712010-02-23 13:46:05 +0000540 var date = MakeDate(day, time);
541
Steve Block6ded16b2010-05-10 14:33:55 +0100542 if (IS_NULL(arr[7])) {
Andrei Popescu31002712010-02-23 13:46:05 +0000543 return TimeClip(UTC(date));
544 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100545 return TimeClip(date - arr[7] * 1000);
Andrei Popescu31002712010-02-23 13:46:05 +0000546 }
547}
548
549
550// ECMA 262 - 15.9.4.3
551function DateUTC(year, month, date, hours, minutes, seconds, ms) {
552 year = ToNumber(year);
553 month = ToNumber(month);
554 var argc = %_ArgumentsLength();
555 date = argc > 2 ? ToNumber(date) : 1;
556 hours = argc > 3 ? ToNumber(hours) : 0;
557 minutes = argc > 4 ? ToNumber(minutes) : 0;
558 seconds = argc > 5 ? ToNumber(seconds) : 0;
559 ms = argc > 6 ? ToNumber(ms) : 0;
Ben Murdoch85b71792012-04-11 18:30:58 +0100560 year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
561 ? 1900 + TO_INTEGER(year) : year;
Andrei Popescu31002712010-02-23 13:46:05 +0000562 var day = MakeDay(year, month, date);
563 var time = MakeTime(hours, minutes, seconds, ms);
Ben Murdoch85b71792012-04-11 18:30:58 +0100564 return %_SetValueOf(this, TimeClip(MakeDate(day, time)));
Andrei Popescu31002712010-02-23 13:46:05 +0000565}
566
567
568// Mozilla-specific extension. Returns the number of milliseconds
569// elapsed since 1 January 1970 00:00:00 UTC.
570function DateNow() {
571 return %DateCurrentTime();
572}
573
574
575// ECMA 262 - 15.9.5.2
576function DateToString() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100577 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000578 if (NUMBER_IS_NAN(t)) return kInvalidDate;
Ben Murdoch85b71792012-04-11 18:30:58 +0100579 var time_zone_string = LocalTimezoneString(t); // May update local offset.
580 return DatePrintString(LocalTimeNoCheck(t)) + time_zone_string;
Andrei Popescu31002712010-02-23 13:46:05 +0000581}
582
583
584// ECMA 262 - 15.9.5.3
585function DateToDateString() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100586 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000587 if (NUMBER_IS_NAN(t)) return kInvalidDate;
Ben Murdoch85b71792012-04-11 18:30:58 +0100588 return DateString(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000589}
590
591
592// ECMA 262 - 15.9.5.4
593function DateToTimeString() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100594 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000595 if (NUMBER_IS_NAN(t)) return kInvalidDate;
Ben Murdoch85b71792012-04-11 18:30:58 +0100596 var time_zone_string = LocalTimezoneString(t); // May update local offset.
597 return TimeString(LocalTimeNoCheck(t)) + time_zone_string;
Andrei Popescu31002712010-02-23 13:46:05 +0000598}
599
600
601// ECMA 262 - 15.9.5.5
602function DateToLocaleString() {
Steve Block1e0659c2011-05-24 12:43:12 +0100603 return %_CallFunction(this, DateToString);
Andrei Popescu31002712010-02-23 13:46:05 +0000604}
605
606
607// ECMA 262 - 15.9.5.6
608function DateToLocaleDateString() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100609 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000610 if (NUMBER_IS_NAN(t)) return kInvalidDate;
Ben Murdoch85b71792012-04-11 18:30:58 +0100611 return LongDateString(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000612}
613
614
615// ECMA 262 - 15.9.5.7
616function DateToLocaleTimeString() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100617 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000618 if (NUMBER_IS_NAN(t)) return kInvalidDate;
Ben Murdoch85b71792012-04-11 18:30:58 +0100619 var lt = LocalTimeNoCheck(t);
620 return TimeString(lt);
Andrei Popescu31002712010-02-23 13:46:05 +0000621}
622
623
624// ECMA 262 - 15.9.5.8
625function DateValueOf() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100626 return DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000627}
628
629
630// ECMA 262 - 15.9.5.9
Andrei Popescu402d9372010-02-26 13:31:12 +0000631function DateGetTime() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100632 return DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000633}
634
635
636// ECMA 262 - 15.9.5.10
637function DateGetFullYear() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100638 var t = DATE_VALUE(this);
639 if (NUMBER_IS_NAN(t)) return t;
640 var cache = Date_cache;
641 if (cache.time === t) return cache.year;
642 return YearFromTime(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000643}
644
645
646// ECMA 262 - 15.9.5.11
647function DateGetUTCFullYear() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100648 var t = DATE_VALUE(this);
649 if (NUMBER_IS_NAN(t)) return t;
650 return YearFromTime(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000651}
652
653
654// ECMA 262 - 15.9.5.12
655function DateGetMonth() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100656 var t = DATE_VALUE(this);
657 if (NUMBER_IS_NAN(t)) return t;
658 return MonthFromTime(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000659}
660
661
662// ECMA 262 - 15.9.5.13
663function DateGetUTCMonth() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100664 var t = DATE_VALUE(this);
665 if (NUMBER_IS_NAN(t)) return t;
666 return MonthFromTime(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000667}
668
669
670// ECMA 262 - 15.9.5.14
671function DateGetDate() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100672 var t = DATE_VALUE(this);
673 if (NUMBER_IS_NAN(t)) return t;
674 return DateFromTime(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000675}
676
677
678// ECMA 262 - 15.9.5.15
679function DateGetUTCDate() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100680 var t = DATE_VALUE(this);
681 return NAN_OR_DATE_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000682}
683
684
685// ECMA 262 - 15.9.5.16
686function DateGetDay() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100687 var t = DATE_VALUE(this);
688 if (NUMBER_IS_NAN(t)) return t;
689 return WeekDay(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000690}
691
692
693// ECMA 262 - 15.9.5.17
694function DateGetUTCDay() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100695 var t = DATE_VALUE(this);
696 if (NUMBER_IS_NAN(t)) return t;
697 return WeekDay(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000698}
699
700
701// ECMA 262 - 15.9.5.18
702function DateGetHours() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100703 var t = DATE_VALUE(this);
704 if (NUMBER_IS_NAN(t)) return t;
705 return HOUR_FROM_TIME(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000706}
707
708
709// ECMA 262 - 15.9.5.19
710function DateGetUTCHours() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100711 var t = DATE_VALUE(this);
712 if (NUMBER_IS_NAN(t)) return t;
713 return HOUR_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000714}
715
716
717// ECMA 262 - 15.9.5.20
718function DateGetMinutes() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100719 var t = DATE_VALUE(this);
720 if (NUMBER_IS_NAN(t)) return t;
721 return MIN_FROM_TIME(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000722}
723
724
725// ECMA 262 - 15.9.5.21
726function DateGetUTCMinutes() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100727 var t = DATE_VALUE(this);
728 return NAN_OR_MIN_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000729}
730
731
732// ECMA 262 - 15.9.5.22
733function DateGetSeconds() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100734 var t = DATE_VALUE(this);
735 if (NUMBER_IS_NAN(t)) return t;
736 return SEC_FROM_TIME(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000737}
738
739
740// ECMA 262 - 15.9.5.23
741function DateGetUTCSeconds() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100742 var t = DATE_VALUE(this);
743 return NAN_OR_SEC_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000744}
745
746
747// ECMA 262 - 15.9.5.24
748function DateGetMilliseconds() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100749 var t = DATE_VALUE(this);
750 if (NUMBER_IS_NAN(t)) return t;
751 return MS_FROM_TIME(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000752}
753
754
755// ECMA 262 - 15.9.5.25
756function DateGetUTCMilliseconds() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100757 var t = DATE_VALUE(this);
758 return NAN_OR_MS_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000759}
760
761
762// ECMA 262 - 15.9.5.26
763function DateGetTimezoneOffset() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100764 var t = DATE_VALUE(this);
765 if (NUMBER_IS_NAN(t)) return t;
766 return (t - LocalTimeNoCheck(t)) / msPerMinute;
Andrei Popescu31002712010-02-23 13:46:05 +0000767}
768
769
770// ECMA 262 - 15.9.5.27
771function DateSetTime(ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100772 if (!IS_DATE(this)) ThrowDateTypeError();
773 return %_SetValueOf(this, TimeClip(ToNumber(ms)));
Andrei Popescu31002712010-02-23 13:46:05 +0000774}
775
776
777// ECMA 262 - 15.9.5.28
778function DateSetMilliseconds(ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100779 var t = LocalTime(DATE_VALUE(this));
Andrei Popescu31002712010-02-23 13:46:05 +0000780 ms = ToNumber(ms);
Ben Murdoch85b71792012-04-11 18:30:58 +0100781 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), SEC_FROM_TIME(t), ms);
782 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
Andrei Popescu31002712010-02-23 13:46:05 +0000783}
784
785
786// ECMA 262 - 15.9.5.29
787function DateSetUTCMilliseconds(ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100788 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000789 ms = ToNumber(ms);
Ben Murdoch85b71792012-04-11 18:30:58 +0100790 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), SEC_FROM_TIME(t), ms);
791 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
Andrei Popescu31002712010-02-23 13:46:05 +0000792}
793
794
795// ECMA 262 - 15.9.5.30
796function DateSetSeconds(sec, ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100797 var t = LocalTime(DATE_VALUE(this));
Andrei Popescu31002712010-02-23 13:46:05 +0000798 sec = ToNumber(sec);
Ben Murdoch85b71792012-04-11 18:30:58 +0100799 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
800 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
801 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
Andrei Popescu31002712010-02-23 13:46:05 +0000802}
803
804
805// ECMA 262 - 15.9.5.31
806function DateSetUTCSeconds(sec, ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100807 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000808 sec = ToNumber(sec);
Ben Murdoch85b71792012-04-11 18:30:58 +0100809 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
810 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
811 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
Andrei Popescu31002712010-02-23 13:46:05 +0000812}
813
814
815// ECMA 262 - 15.9.5.33
816function DateSetMinutes(min, sec, ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100817 var t = LocalTime(DATE_VALUE(this));
Andrei Popescu31002712010-02-23 13:46:05 +0000818 min = ToNumber(min);
819 var argc = %_ArgumentsLength();
Ben Murdoch85b71792012-04-11 18:30:58 +0100820 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
821 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
822 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
823 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
Andrei Popescu31002712010-02-23 13:46:05 +0000824}
825
826
827// ECMA 262 - 15.9.5.34
828function DateSetUTCMinutes(min, sec, ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100829 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000830 min = ToNumber(min);
831 var argc = %_ArgumentsLength();
Ben Murdoch85b71792012-04-11 18:30:58 +0100832 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
833 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
834 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
835 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
Andrei Popescu31002712010-02-23 13:46:05 +0000836}
837
838
839// ECMA 262 - 15.9.5.35
840function DateSetHours(hour, min, sec, ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100841 var t = LocalTime(DATE_VALUE(this));
Andrei Popescu31002712010-02-23 13:46:05 +0000842 hour = ToNumber(hour);
843 var argc = %_ArgumentsLength();
Ben Murdoch85b71792012-04-11 18:30:58 +0100844 min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
845 sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
846 ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000847 var time = MakeTime(hour, min, sec, ms);
Ben Murdoch85b71792012-04-11 18:30:58 +0100848 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
Andrei Popescu31002712010-02-23 13:46:05 +0000849}
850
851
852// ECMA 262 - 15.9.5.34
853function DateSetUTCHours(hour, min, sec, ms) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100854 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000855 hour = ToNumber(hour);
856 var argc = %_ArgumentsLength();
Ben Murdoch85b71792012-04-11 18:30:58 +0100857 min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
858 sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
859 ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000860 var time = MakeTime(hour, min, sec, ms);
Ben Murdoch85b71792012-04-11 18:30:58 +0100861 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
Andrei Popescu31002712010-02-23 13:46:05 +0000862}
863
864
865// ECMA 262 - 15.9.5.36
866function DateSetDate(date) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100867 var t = LocalTime(DATE_VALUE(this));
Andrei Popescu31002712010-02-23 13:46:05 +0000868 date = ToNumber(date);
Ben Murdoch85b71792012-04-11 18:30:58 +0100869 var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
870 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
Andrei Popescu31002712010-02-23 13:46:05 +0000871}
872
873
874// ECMA 262 - 15.9.5.37
875function DateSetUTCDate(date) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100876 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000877 date = ToNumber(date);
Ben Murdoch85b71792012-04-11 18:30:58 +0100878 var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
879 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
Andrei Popescu31002712010-02-23 13:46:05 +0000880}
881
882
883// ECMA 262 - 15.9.5.38
884function DateSetMonth(month, date) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100885 var t = LocalTime(DATE_VALUE(this));
Andrei Popescu31002712010-02-23 13:46:05 +0000886 month = ToNumber(month);
Ben Murdoch85b71792012-04-11 18:30:58 +0100887 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
888 var day = MakeDay(YearFromTime(t), month, date);
889 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
Andrei Popescu31002712010-02-23 13:46:05 +0000890}
891
892
893// ECMA 262 - 15.9.5.39
894function DateSetUTCMonth(month, date) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100895 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000896 month = ToNumber(month);
Ben Murdoch85b71792012-04-11 18:30:58 +0100897 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
898 var day = MakeDay(YearFromTime(t), month, date);
899 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
Andrei Popescu31002712010-02-23 13:46:05 +0000900}
901
902
903// ECMA 262 - 15.9.5.40
904function DateSetFullYear(year, month, date) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100905 var t = DATE_VALUE(this);
906 t = NUMBER_IS_NAN(t) ? 0 : LocalTimeNoCheck(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000907 year = ToNumber(year);
908 var argc = %_ArgumentsLength();
Ben Murdoch85b71792012-04-11 18:30:58 +0100909 month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
910 date = argc < 3 ? DateFromTime(t) : ToNumber(date);
Andrei Popescu31002712010-02-23 13:46:05 +0000911 var day = MakeDay(year, month, date);
Ben Murdoch85b71792012-04-11 18:30:58 +0100912 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
Andrei Popescu31002712010-02-23 13:46:05 +0000913}
914
915
916// ECMA 262 - 15.9.5.41
917function DateSetUTCFullYear(year, month, date) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100918 var t = DATE_VALUE(this);
919 if (NUMBER_IS_NAN(t)) t = 0;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100920 var argc = %_ArgumentsLength();
Ben Murdoch85b71792012-04-11 18:30:58 +0100921 year = ToNumber(year);
922 month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
923 date = argc < 3 ? DateFromTime(t) : ToNumber(date);
Andrei Popescu31002712010-02-23 13:46:05 +0000924 var day = MakeDay(year, month, date);
Ben Murdoch85b71792012-04-11 18:30:58 +0100925 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
Andrei Popescu31002712010-02-23 13:46:05 +0000926}
927
928
929// ECMA 262 - 15.9.5.42
930function DateToUTCString() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100931 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000932 if (NUMBER_IS_NAN(t)) return kInvalidDate;
933 // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
Ben Murdoch85b71792012-04-11 18:30:58 +0100934 return WeekDays[WeekDay(t)] + ', '
935 + TwoDigitString(DateFromTime(t)) + ' '
936 + Months[MonthFromTime(t)] + ' '
937 + YearFromTime(t) + ' '
938 + TimeString(t) + ' GMT';
Andrei Popescu31002712010-02-23 13:46:05 +0000939}
940
941
942// ECMA 262 - B.2.4
943function DateGetYear() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100944 var t = DATE_VALUE(this);
945 if (NUMBER_IS_NAN(t)) return $NaN;
946 return YearFromTime(LocalTimeNoCheck(t)) - 1900;
Andrei Popescu31002712010-02-23 13:46:05 +0000947}
948
949
950// ECMA 262 - B.2.5
951function DateSetYear(year) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100952 var t = LocalTime(DATE_VALUE(this));
953 if (NUMBER_IS_NAN(t)) t = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000954 year = ToNumber(year);
Ben Murdoch85b71792012-04-11 18:30:58 +0100955 if (NUMBER_IS_NAN(year)) return %_SetValueOf(this, $NaN);
Andrei Popescu31002712010-02-23 13:46:05 +0000956 year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
957 ? 1900 + TO_INTEGER(year) : year;
Ben Murdoch85b71792012-04-11 18:30:58 +0100958 var day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
959 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
Andrei Popescu31002712010-02-23 13:46:05 +0000960}
961
962
963// ECMA 262 - B.2.6
964//
965// Notice that this does not follow ECMA 262 completely. ECMA 262
966// says that toGMTString should be the same Function object as
967// toUTCString. JSC does not do this, so for compatibility we do not
968// do that either. Instead, we create a new function whose name
969// property will return toGMTString.
970function DateToGMTString() {
Steve Block1e0659c2011-05-24 12:43:12 +0100971 return %_CallFunction(this, DateToUTCString);
Andrei Popescu31002712010-02-23 13:46:05 +0000972}
973
974
975function PadInt(n, digits) {
976 if (digits == 1) return n;
977 return n < MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
978}
979
980
981function DateToISOString() {
Ben Murdoch85b71792012-04-11 18:30:58 +0100982 var t = DATE_VALUE(this);
983 if (NUMBER_IS_NAN(t)) return kInvalidDate;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000984 var year = this.getUTCFullYear();
985 var year_string;
986 if (year >= 0 && year <= 9999) {
987 year_string = PadInt(year, 4);
988 } else {
989 if (year < 0) {
990 year_string = "-" + PadInt(-year, 6);
991 } else {
992 year_string = "+" + PadInt(year, 6);
993 }
994 }
995 return year_string +
Ben Murdochb0fe1622011-05-05 13:52:32 +0100996 '-' + PadInt(this.getUTCMonth() + 1, 2) +
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000997 '-' + PadInt(this.getUTCDate(), 2) +
Ben Murdochb0fe1622011-05-05 13:52:32 +0100998 'T' + PadInt(this.getUTCHours(), 2) +
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000999 ':' + PadInt(this.getUTCMinutes(), 2) +
Ben Murdochb0fe1622011-05-05 13:52:32 +01001000 ':' + PadInt(this.getUTCSeconds(), 2) +
Andrei Popescu31002712010-02-23 13:46:05 +00001001 '.' + PadInt(this.getUTCMilliseconds(), 3) +
1002 'Z';
1003}
1004
1005
1006function DateToJSON(key) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001007 var o = ToObject(this);
1008 var tv = DefaultNumber(o);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001009 if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
1010 return null;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001011 }
1012 return o.toISOString();
1013}
1014
1015
1016function ResetDateCache() {
Ben Murdoch85b71792012-04-11 18:30:58 +01001017
1018 // Reset the local_time_offset:
1019 local_time_offset = %DateLocalTimeOffset();
1020
1021 // Reset the DST offset cache:
1022 var cache = DST_offset_cache;
1023 cache.offset = 0;
1024 cache.start = 0;
1025 cache.end = -1;
1026 cache.increment = 0;
1027 cache.initial_increment = 19 * msPerDay;
1028
Ben Murdochb0fe1622011-05-05 13:52:32 +01001029 // Reset the timezone cache:
1030 timezone_cache_time = $NaN;
1031 timezone_cache_timezone = undefined;
1032
Ben Murdoch85b71792012-04-11 18:30:58 +01001033 // Reset the ltcache:
1034 ltcache.key = null;
1035 ltcache.val = null;
1036
1037 // Reset the ymd_from_time_cache:
1038 ymd_from_time_cache = [$NaN, $NaN, $NaN];
1039 ymd_from_time_cached_time = $NaN;
1040
Ben Murdochb0fe1622011-05-05 13:52:32 +01001041 // Reset the date cache:
1042 cache = Date_cache;
1043 cache.time = $NaN;
Ben Murdoch85b71792012-04-11 18:30:58 +01001044 cache.year = $NaN;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001045 cache.string = null;
Andrei Popescu31002712010-02-23 13:46:05 +00001046}
1047
1048
1049// -------------------------------------------------------------------
1050
Ben Murdoch589d6972011-11-30 16:04:58 +00001051function SetUpDate() {
1052 %CheckIsBootstrapping();
1053 // Set up non-enumerable properties of the Date object itself.
Andrei Popescu31002712010-02-23 13:46:05 +00001054 InstallFunctions($Date, DONT_ENUM, $Array(
1055 "UTC", DateUTC,
1056 "parse", DateParse,
1057 "now", DateNow
1058 ));
1059
Ben Murdoch589d6972011-11-30 16:04:58 +00001060 // Set up non-enumerable constructor property of the Date prototype object.
Andrei Popescu31002712010-02-23 13:46:05 +00001061 %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
1062
Ben Murdoch589d6972011-11-30 16:04:58 +00001063 // Set up non-enumerable functions of the Date prototype object and
Andrei Popescu31002712010-02-23 13:46:05 +00001064 // set their names.
Ben Murdoch85b71792012-04-11 18:30:58 +01001065 InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
Andrei Popescu31002712010-02-23 13:46:05 +00001066 "toString", DateToString,
1067 "toDateString", DateToDateString,
1068 "toTimeString", DateToTimeString,
1069 "toLocaleString", DateToLocaleString,
1070 "toLocaleDateString", DateToLocaleDateString,
1071 "toLocaleTimeString", DateToLocaleTimeString,
1072 "valueOf", DateValueOf,
1073 "getTime", DateGetTime,
1074 "getFullYear", DateGetFullYear,
1075 "getUTCFullYear", DateGetUTCFullYear,
1076 "getMonth", DateGetMonth,
1077 "getUTCMonth", DateGetUTCMonth,
1078 "getDate", DateGetDate,
1079 "getUTCDate", DateGetUTCDate,
1080 "getDay", DateGetDay,
1081 "getUTCDay", DateGetUTCDay,
1082 "getHours", DateGetHours,
1083 "getUTCHours", DateGetUTCHours,
1084 "getMinutes", DateGetMinutes,
1085 "getUTCMinutes", DateGetUTCMinutes,
1086 "getSeconds", DateGetSeconds,
1087 "getUTCSeconds", DateGetUTCSeconds,
1088 "getMilliseconds", DateGetMilliseconds,
1089 "getUTCMilliseconds", DateGetUTCMilliseconds,
1090 "getTimezoneOffset", DateGetTimezoneOffset,
1091 "setTime", DateSetTime,
1092 "setMilliseconds", DateSetMilliseconds,
1093 "setUTCMilliseconds", DateSetUTCMilliseconds,
1094 "setSeconds", DateSetSeconds,
1095 "setUTCSeconds", DateSetUTCSeconds,
1096 "setMinutes", DateSetMinutes,
1097 "setUTCMinutes", DateSetUTCMinutes,
1098 "setHours", DateSetHours,
1099 "setUTCHours", DateSetUTCHours,
1100 "setDate", DateSetDate,
1101 "setUTCDate", DateSetUTCDate,
1102 "setMonth", DateSetMonth,
1103 "setUTCMonth", DateSetUTCMonth,
1104 "setFullYear", DateSetFullYear,
1105 "setUTCFullYear", DateSetUTCFullYear,
1106 "toGMTString", DateToGMTString,
1107 "toUTCString", DateToUTCString,
1108 "getYear", DateGetYear,
1109 "setYear", DateSetYear,
1110 "toISOString", DateToISOString,
1111 "toJSON", DateToJSON
1112 ));
1113}
1114
Ben Murdoch589d6972011-11-30 16:04:58 +00001115SetUpDate();