blob: 79b846d4a7060efc938990330cf8396b07224073 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000029// This file relies on the fact that the following declarations have been made
30// in v8natives.js:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000031// const $isFinite = GlobalIsFinite;
32
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033// -------------------------------------------------------------------
34
35// This file contains date support implemented in JavaScript.
36
37
38// 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.
41const $Date = global.Date;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000043// Helper function to throw error.
44function ThrowDateTypeError() {
45 throw new $TypeError('this is not a Date object.');
46}
47
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048// ECMA 262 - 5.2
49function Modulo(value, remainder) {
50 var mod = value % remainder;
ager@chromium.org3bf7b912008-11-17 09:09:45 +000051 // Guard against returning -0.
52 if (mod == 0) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053 return mod >= 0 ? mod : mod + remainder;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000054}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055
56
57function TimeWithinDay(time) {
58 return Modulo(time, msPerDay);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000059}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
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;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000067}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69
70function DayFromYear(year) {
71 return 365 * (year-1970)
ager@chromium.org7c537e22008-10-16 08:43:32 +000072 + FLOOR((year-1969)/4)
73 - FLOOR((year-1901)/100)
74 + FLOOR((year-1601)/400);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000075}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076
77
78function TimeFromYear(year) {
79 return msPerDay * DayFromYear(year);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000080}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000081
82
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083function InLeapYear(time) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000084 return DaysInYear(YearFromTime(time)) - 365; // Returns 1 or 0.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000085}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000086
87
88// ECMA 262 - 15.9.1.9
89function EquivalentYear(year) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +000090 // Returns an equivalent year in the range [2008-2035] matching
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091 // - leap year.
92 // - week day of first day.
93 var time = TimeFromYear(year);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000094 var recent_year = (InLeapYear(time) == 0 ? 1967 : 1956) +
ager@chromium.orga74f0da2008-12-03 16:05:52 +000095 (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;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000099}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101
102function EquivalentTime(t) {
103 // The issue here is that some library calls don't work right for dates
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000104 // that cannot be represented using a non-negative signed 32 bit integer
105 // (measured in whole seconds based on the 1970 epoch).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106 // We solve this by mapping the time to a year with same leap-year-ness
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000107 // and same starting day for the year. The ECMAscript specification says
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000108 // we must do this, but for compatibility with other browsers, we use
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000109 // the actual year if it is in the range 1970..2037
110 if (t >= 0 && t <= 2.1e12) return t;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000111
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000112 var day = MakeDay(EquivalentYear(YearFromTime(t)),
113 MonthFromTime(t),
114 DateFromTime(t));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000115 return MakeDate(day, TimeWithinDay(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000116}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000118
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000119// 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
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000127// where we know the cache is valid.
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000128// When the cache is valid, local_time_offset is also valid.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000129var 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.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000135 increment: 0,
136 initial_increment: 19 * msPerDay
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000137};
138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000140// NOTE: The implementation relies on the fact that no time zones have
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000141// 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//
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000147// If this function is called with NaN it returns NaN.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148function DaylightSavingsOffset(t) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000149 // 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
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000160 // 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
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000165 // 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;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000175 cache.increment = cache.initial_increment;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000176 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;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000186 cache.increment = cache.initial_increment;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000187 } 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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000200
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000201 // 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 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000205 // 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.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208 var offset = %DateDaylightSavingsOffset(EquivalentTime(t));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000209 cache.offset = offset;
210 cache.start = cache.end = t;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000211 cache.increment = cache.initial_increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 return offset;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000213}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214
215
216var timezone_cache_time = $NaN;
217var timezone_cache_timezone;
218
219function LocalTimezone(t) {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000220 if (NUMBER_IS_NAN(t)) return "";
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000221 if (t == timezone_cache_time) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 return timezone_cache_timezone;
223 }
224 var timezone = %DateLocalTimezone(EquivalentTime(t));
225 timezone_cache_time = t;
226 timezone_cache_timezone = timezone;
227 return timezone;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000228}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000229
230
231function WeekDay(time) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000232 return Modulo(DAY(time) + 4, 7);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000233}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234
235
236function LocalTime(time) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000237 if (NUMBER_IS_NAN(time)) return time;
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000238 // DaylightSavingsOffset called before local_time_offset used.
239 return time + DaylightSavingsOffset(time) + local_time_offset;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000240}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000242
243var ltcache = {
vegorov@chromium.org42841962010-10-18 11:18:59 +0000244 key: null,
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000245 val: null
246};
247
ager@chromium.org7c537e22008-10-16 08:43:32 +0000248function LocalTimeNoCheck(time) {
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000249 var ltc = ltcache;
250 if (%_ObjectEquals(time, ltc.key)) return ltc.val;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000251
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000252 // Inline the DST offset cache checks for speed.
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000253 // The cache is hit, or DaylightSavingsOffset is called,
254 // before local_time_offset is used.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000255 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 }
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000261 ltc.key = time;
262 return (ltc.val = time + local_time_offset + dst_offset);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000263}
264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265
266function UTC(time) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000267 if (NUMBER_IS_NAN(time)) return time;
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000268 // local_time_offset is needed before the call to DaylightSavingsOffset,
269 // so it may be uninitialized.
270 if (IS_UNDEFINED(local_time_offset)) {
271 local_time_offset = %DateLocalTimeOffset();
272 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000273 var tmp = time - local_time_offset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000274 return tmp - DaylightSavingsOffset(tmp);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000275}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276
277
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000278// 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);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000288}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000289
290
291// ECMA 262 - 15.9.1.12
292function TimeInYear(year) {
293 return DaysInYear(year) * msPerDay;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000294}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295
296
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000297var 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) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000302 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000303 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];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311}
312
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000313function MonthFromTime(t) {
314 if (t !== ymd_from_time_cached_time) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000315 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000316 return $NaN;
317 }
318 %DateYMDFromTime(t, ymd_from_time_cache);
319 ymd_from_time_cached_time = t
320 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000322 return ymd_from_time_cache[1];
323}
324
325function DateFromTime(t) {
326 if (t !== ymd_from_time_cached_time) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000327 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328 return $NaN;
329 }
330
331 %DateYMDFromTime(t, ymd_from_time_cache);
332 ymd_from_time_cached_time = t
ager@chromium.org381abbb2009-02-25 13:23:22 +0000333 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000334
335 return ymd_from_time_cache[2];
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337
ager@chromium.org7c537e22008-10-16 08:43:32 +0000338
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000348 // 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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000353 if (year < kMinYear || year > kMaxYear ||
354 month < kMinMonth || month > kMaxMonth ||
355 date < kMinDate || date > kMaxDate) {
356 return $NaN;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357 }
358
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000359 // Now we rely on year, month and date being SMIs.
360 return %DateMakeDay(year, month, date);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000361}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362
363
364// ECMA 262 - 15.9.1.13
365function MakeDate(day, time) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000366 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;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000374}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375
376
377// ECMA 262 - 15.9.1.14
378function TimeClip(time) {
379 if (!$isFinite(time)) return $NaN;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000380 if ($abs(time) > MAX_TIME_MS) return $NaN;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 return TO_INTEGER(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000382}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383
384
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000385// 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,
390 // Cached year when interpreting the time as a local time. Only
391 // valid when the time matches cached time.
392 year: $NaN,
393 // String input for which the cached time is valid.
394 string: null
395};
396
397
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000399 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();
409
410 } else if (argc == 1) {
411 if (IS_NUMBER(year)) {
412 value = TimeClip(year);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000413
414 } 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);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000422 if (!NUMBER_IS_NAN(value)) {
423 cache.time = value;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000424 cache.year = YearFromTime(LocalTimeNoCheck(value));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000425 cache.string = year;
426 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000427 }
428
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000429 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430 // According to ECMA 262, no hint should be given for this
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000431 // conversion. However, ToPrimitive defaults to STRING_HINT for
432 // Date objects which will lose precision when the Date
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000433 // constructor is called with another Date object as its
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000434 // 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.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 var time = ToPrimitive(year, NUMBER_HINT);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000438 value = IS_STRING(time) ? DateParse(time) : TimeClip(ToNumber(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000440
441 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000442 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;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000449 year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000450 ? 1900 + TO_INTEGER(year) : year;
451 var day = MakeDay(year, month, date);
452 var time = MakeTime(hours, minutes, seconds, ms);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000453 value = TimeClip(UTC(MakeDate(day, time)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000455 %_SetValueOf(this, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456});
457
458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459%FunctionSetPrototype($Date, new $Date($NaN));
460
461
462var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
463var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
464
465
466function TwoDigitString(value) {
467 return value < 10 ? "0" + value : "" + value;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000468}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000469
470
471function DateString(time) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472 return WeekDays[WeekDay(time)] + ' '
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000473 + Months[MonthFromTime(time)] + ' '
474 + TwoDigitString(DateFromTime(time)) + ' '
475 + YearFromTime(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000476}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477
478
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000479var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
480var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
481
482
483function LongDateString(time) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000484 return LongWeekDays[WeekDay(time)] + ', '
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000485 + LongMonths[MonthFromTime(time)] + ' '
486 + TwoDigitString(DateFromTime(time)) + ', '
487 + YearFromTime(time);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000488}
489
490
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491function TimeString(time) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000492 return TwoDigitString(HOUR_FROM_TIME(time)) + ':'
493 + TwoDigitString(MIN_FROM_TIME(time)) + ':'
494 + TwoDigitString(SEC_FROM_TIME(time));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000495}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496
497
498function LocalTimezoneString(time) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000499 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 }
512
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000513 var timezoneOffset =
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000514 (DaylightSavingsOffset(time) + local_time_offset) / msPerMinute;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515 var sign = (timezoneOffset >= 0) ? 1 : -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000516 var hours = FLOOR((sign * timezoneOffset)/60);
517 var min = FLOOR((sign * timezoneOffset)%60);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000518 var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
519 TwoDigitString(hours) + TwoDigitString(min);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000520 return gmt + ' (' + timezone + ')';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000521}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522
523
524function DatePrintString(time) {
525 return DateString(time) + ' ' + TimeString(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000526}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527
528// -------------------------------------------------------------------
529
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000530// Reused output buffer. Used when parsing date strings.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000531var parse_buffer = $Array(8);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532
533// ECMA 262 - 15.9.4.2
534function DateParse(string) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000535 var arr = %DateParseString(ToString(string), parse_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536 if (IS_NULL(arr)) return $NaN;
537
538 var day = MakeDay(arr[0], arr[1], arr[2]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000539 var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 var date = MakeDate(day, time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000541
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000542 if (IS_NULL(arr[7])) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543 return TimeClip(UTC(date));
544 } else {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000545 return TimeClip(date - arr[7] * 1000);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000547}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548
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;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000560 year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561 ? 1900 + TO_INTEGER(year) : year;
562 var day = MakeDay(year, month, date);
563 var time = MakeTime(hours, minutes, seconds, ms);
564 return %_SetValueOf(this, TimeClip(MakeDate(day, time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000565}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566
567
568// Mozilla-specific extension. Returns the number of milliseconds
569// elapsed since 1 January 1970 00:00:00 UTC.
570function DateNow() {
mads.s.ager31e71382008-08-13 09:32:07 +0000571 return %DateCurrentTime();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000572}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573
574
575// ECMA 262 - 15.9.5.2
576function DateToString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000577 var t = DATE_VALUE(this);
578 if (NUMBER_IS_NAN(t)) return kInvalidDate;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000579 var time_zone_string = LocalTimezoneString(t); // May update local offset.
580 return DatePrintString(LocalTimeNoCheck(t)) + time_zone_string;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000581}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000582
583
584// ECMA 262 - 15.9.5.3
585function DateToDateString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000586 var t = DATE_VALUE(this);
587 if (NUMBER_IS_NAN(t)) return kInvalidDate;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000588 return DateString(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000589}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000590
591
592// ECMA 262 - 15.9.5.4
593function DateToTimeString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000594 var t = DATE_VALUE(this);
595 if (NUMBER_IS_NAN(t)) return kInvalidDate;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000596 var time_zone_string = LocalTimezoneString(t); // May update local offset.
597 return TimeString(LocalTimeNoCheck(t)) + time_zone_string;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000598}
599
600
601// ECMA 262 - 15.9.5.5
602function DateToLocaleString() {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000603 return %_CallFunction(this, DateToString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000604}
605
606
607// ECMA 262 - 15.9.5.6
608function DateToLocaleDateString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000609 var t = DATE_VALUE(this);
610 if (NUMBER_IS_NAN(t)) return kInvalidDate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000611 return LongDateString(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000612}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000613
614
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000615// ECMA 262 - 15.9.5.7
616function DateToLocaleTimeString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000617 var t = DATE_VALUE(this);
618 if (NUMBER_IS_NAN(t)) return kInvalidDate;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000619 var lt = LocalTimeNoCheck(t);
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000620 return TimeString(lt);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000621}
622
623
624// ECMA 262 - 15.9.5.8
625function DateValueOf() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000626 return DATE_VALUE(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000627}
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000628
629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630// ECMA 262 - 15.9.5.9
631function DateGetTime() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000632 return DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633}
634
635
636// ECMA 262 - 15.9.5.10
637function DateGetFullYear() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000638 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;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000642 return YearFromTime(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000643}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644
645
646// ECMA 262 - 15.9.5.11
647function DateGetUTCFullYear() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000648 var t = DATE_VALUE(this);
649 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000650 return YearFromTime(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000651}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652
653
654// ECMA 262 - 15.9.5.12
655function DateGetMonth() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000656 var t = DATE_VALUE(this);
657 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000658 return MonthFromTime(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000659}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660
661
662// ECMA 262 - 15.9.5.13
663function DateGetUTCMonth() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000664 var t = DATE_VALUE(this);
665 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000666 return MonthFromTime(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000667}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668
669
670// ECMA 262 - 15.9.5.14
671function DateGetDate() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000672 var t = DATE_VALUE(this);
673 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000674 return DateFromTime(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000675}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676
677
678// ECMA 262 - 15.9.5.15
679function DateGetUTCDate() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000680 var t = DATE_VALUE(this);
681 return NAN_OR_DATE_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000682}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683
684
685// ECMA 262 - 15.9.5.16
686function DateGetDay() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000687 var t = DATE_VALUE(this);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000688 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000689 return WeekDay(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000690}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691
692
693// ECMA 262 - 15.9.5.17
694function DateGetUTCDay() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000695 var t = DATE_VALUE(this);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000696 if (NUMBER_IS_NAN(t)) return t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697 return WeekDay(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000698}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699
700
701// ECMA 262 - 15.9.5.18
702function DateGetHours() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000703 var t = DATE_VALUE(this);
704 if (NUMBER_IS_NAN(t)) return t;
705 return HOUR_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000706}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707
708
709// ECMA 262 - 15.9.5.19
710function DateGetUTCHours() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000711 var t = DATE_VALUE(this);
712 if (NUMBER_IS_NAN(t)) return t;
713 return HOUR_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000714}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715
716
717// ECMA 262 - 15.9.5.20
718function DateGetMinutes() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000719 var t = DATE_VALUE(this);
720 if (NUMBER_IS_NAN(t)) return t;
721 return MIN_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000722}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000723
724
725// ECMA 262 - 15.9.5.21
726function DateGetUTCMinutes() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000727 var t = DATE_VALUE(this);
728 return NAN_OR_MIN_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000729}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730
731
732// ECMA 262 - 15.9.5.22
733function DateGetSeconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000734 var t = DATE_VALUE(this);
735 if (NUMBER_IS_NAN(t)) return t;
736 return SEC_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000737}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000738
739
740// ECMA 262 - 15.9.5.23
741function DateGetUTCSeconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000742 var t = DATE_VALUE(this);
743 return NAN_OR_SEC_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000744}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745
746
747// ECMA 262 - 15.9.5.24
748function DateGetMilliseconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000749 var t = DATE_VALUE(this);
750 if (NUMBER_IS_NAN(t)) return t;
751 return MS_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000752}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000753
754
755// ECMA 262 - 15.9.5.25
756function DateGetUTCMilliseconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000757 var t = DATE_VALUE(this);
758 return NAN_OR_MS_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000759}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760
761
762// ECMA 262 - 15.9.5.26
763function DateGetTimezoneOffset() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000764 var t = DATE_VALUE(this);
765 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000766 return (t - LocalTimeNoCheck(t)) / msPerMinute;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000767}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000768
769
770// ECMA 262 - 15.9.5.27
771function DateSetTime(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000772 if (!IS_DATE(this)) ThrowDateTypeError();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 return %_SetValueOf(this, TimeClip(ToNumber(ms)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000774}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000775
776
777// ECMA 262 - 15.9.5.28
778function DateSetMilliseconds(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000779 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780 ms = ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000781 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))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000783}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784
785
786// ECMA 262 - 15.9.5.29
787function DateSetUTCMilliseconds(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000788 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789 ms = ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000790 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)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000792}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793
794
795// ECMA 262 - 15.9.5.30
796function DateSetSeconds(sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000797 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798 sec = ToNumber(sec);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000799 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000800 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
801 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000802}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803
804
805// ECMA 262 - 15.9.5.31
806function DateSetUTCSeconds(sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000807 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 sec = ToNumber(sec);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000809 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000810 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
811 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000812}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813
814
815// ECMA 262 - 15.9.5.33
816function DateSetMinutes(min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000817 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818 min = ToNumber(min);
819 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000820 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
821 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000822 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
823 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000824}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000825
826
827// ECMA 262 - 15.9.5.34
828function DateSetUTCMinutes(min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000829 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830 min = ToNumber(min);
831 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000832 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
833 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000834 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
835 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000836}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837
838
839// ECMA 262 - 15.9.5.35
840function DateSetHours(hour, min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000841 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842 hour = ToNumber(hour);
843 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000844 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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 var time = MakeTime(hour, min, sec, ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000848 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000849}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850
851
852// ECMA 262 - 15.9.5.34
853function DateSetUTCHours(hour, min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000854 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 hour = ToNumber(hour);
856 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000857 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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860 var time = MakeTime(hour, min, sec, ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000861 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000862}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863
864
865// ECMA 262 - 15.9.5.36
866function DateSetDate(date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000867 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868 date = ToNumber(date);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000869 var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000871}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872
873
874// ECMA 262 - 15.9.5.37
875function DateSetUTCDate(date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000876 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000877 date = ToNumber(date);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000878 var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000880}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881
882
883// ECMA 262 - 15.9.5.38
884function DateSetMonth(month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000885 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 month = ToNumber(month);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000887 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000888 var day = MakeDay(YearFromTime(t), month, date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000890}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891
892
893// ECMA 262 - 15.9.5.39
894function DateSetUTCMonth(month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000895 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896 month = ToNumber(month);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000897 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000898 var day = MakeDay(YearFromTime(t), month, date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000900}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901
902
903// ECMA 262 - 15.9.5.40
904function DateSetFullYear(year, month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000905 var t = DATE_VALUE(this);
906 t = NUMBER_IS_NAN(t) ? 0 : LocalTimeNoCheck(t);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907 year = ToNumber(year);
908 var argc = %_ArgumentsLength();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000909 month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
910 date = argc < 3 ? DateFromTime(t) : ToNumber(date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911 var day = MakeDay(year, month, date);
912 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000913}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914
915
916// ECMA 262 - 15.9.5.41
917function DateSetUTCFullYear(year, month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000918 var t = DATE_VALUE(this);
919 if (NUMBER_IS_NAN(t)) t = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920 var argc = %_ArgumentsLength();
921 year = ToNumber(year);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000922 month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
923 date = argc < 3 ? DateFromTime(t) : ToNumber(date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924 var day = MakeDay(year, month, date);
925 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000926}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927
928
929// ECMA 262 - 15.9.5.42
930function DateToUTCString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000931 var t = DATE_VALUE(this);
932 if (NUMBER_IS_NAN(t)) return kInvalidDate;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
934 return WeekDays[WeekDay(t)] + ', '
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000935 + TwoDigitString(DateFromTime(t)) + ' '
936 + Months[MonthFromTime(t)] + ' '
937 + YearFromTime(t) + ' '
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 + TimeString(t) + ' GMT';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000939}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940
941
942// ECMA 262 - B.2.4
943function DateGetYear() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000944 var t = DATE_VALUE(this);
945 if (NUMBER_IS_NAN(t)) return $NaN;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000946 return YearFromTime(LocalTimeNoCheck(t)) - 1900;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000947}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948
949
950// ECMA 262 - B.2.5
951function DateSetYear(year) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000952 var t = LocalTime(DATE_VALUE(this));
953 if (NUMBER_IS_NAN(t)) t = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954 year = ToNumber(year);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000955 if (NUMBER_IS_NAN(year)) return %_SetValueOf(this, $NaN);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
957 ? 1900 + TO_INTEGER(year) : year;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000958 var day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +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() {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000971 return %_CallFunction(this, DateToUTCString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000972}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000973
974
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000975function PadInt(n, digits) {
976 if (digits == 1) return n;
977 return n < MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000978}
979
980
981function DateToISOString() {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000982 var t = DATE_VALUE(this);
983 if (NUMBER_IS_NAN(t)) return kInvalidDate;
ricow@chromium.org4f693d62011-07-04 14:01:31 +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 +
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000996 '-' + PadInt(this.getUTCMonth() + 1, 2) +
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000997 '-' + PadInt(this.getUTCDate(), 2) +
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000998 'T' + PadInt(this.getUTCHours(), 2) +
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000999 ':' + PadInt(this.getUTCMinutes(), 2) +
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001000 ':' + PadInt(this.getUTCSeconds(), 2) +
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001001 '.' + PadInt(this.getUTCMilliseconds(), 3) +
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001002 'Z';
1003}
1004
1005
1006function DateToJSON(key) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001007 var o = ToObject(this);
1008 var tv = DefaultNumber(o);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001009 if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
1010 return null;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001011 }
1012 return o.toISOString();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001013}
1014
1015
whesse@chromium.org023421e2010-12-21 12:19:12 +00001016function ResetDateCache() {
1017
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
1029 // Reset the timezone cache:
1030 timezone_cache_time = $NaN;
1031 timezone_cache_timezone = undefined;
1032
1033 // 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
1041 // Reset the date cache:
1042 cache = Date_cache;
1043 cache.time = $NaN;
1044 cache.year = $NaN;
1045 cache.string = null;
1046}
1047
1048
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049// -------------------------------------------------------------------
1050
1051function SetupDate() {
1052 // Setup non-enumerable properties of the Date object itself.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001053 InstallFunctions($Date, DONT_ENUM, $Array(
1054 "UTC", DateUTC,
1055 "parse", DateParse,
1056 "now", DateNow
1057 ));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001059 // Setup non-enumerable constructor property of the Date prototype object.
1060 %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
1061
1062 // Setup non-enumerable functions of the Date prototype object and
1063 // set their names.
ager@chromium.org9085a012009-05-11 19:22:57 +00001064 InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001065 "toString", DateToString,
1066 "toDateString", DateToDateString,
1067 "toTimeString", DateToTimeString,
1068 "toLocaleString", DateToLocaleString,
1069 "toLocaleDateString", DateToLocaleDateString,
1070 "toLocaleTimeString", DateToLocaleTimeString,
1071 "valueOf", DateValueOf,
1072 "getTime", DateGetTime,
1073 "getFullYear", DateGetFullYear,
1074 "getUTCFullYear", DateGetUTCFullYear,
1075 "getMonth", DateGetMonth,
1076 "getUTCMonth", DateGetUTCMonth,
1077 "getDate", DateGetDate,
1078 "getUTCDate", DateGetUTCDate,
1079 "getDay", DateGetDay,
1080 "getUTCDay", DateGetUTCDay,
1081 "getHours", DateGetHours,
1082 "getUTCHours", DateGetUTCHours,
1083 "getMinutes", DateGetMinutes,
1084 "getUTCMinutes", DateGetUTCMinutes,
1085 "getSeconds", DateGetSeconds,
1086 "getUTCSeconds", DateGetUTCSeconds,
1087 "getMilliseconds", DateGetMilliseconds,
1088 "getUTCMilliseconds", DateGetUTCMilliseconds,
1089 "getTimezoneOffset", DateGetTimezoneOffset,
1090 "setTime", DateSetTime,
1091 "setMilliseconds", DateSetMilliseconds,
1092 "setUTCMilliseconds", DateSetUTCMilliseconds,
1093 "setSeconds", DateSetSeconds,
1094 "setUTCSeconds", DateSetUTCSeconds,
1095 "setMinutes", DateSetMinutes,
1096 "setUTCMinutes", DateSetUTCMinutes,
1097 "setHours", DateSetHours,
1098 "setUTCHours", DateSetUTCHours,
1099 "setDate", DateSetDate,
1100 "setUTCDate", DateSetUTCDate,
1101 "setMonth", DateSetMonth,
1102 "setUTCMonth", DateSetUTCMonth,
1103 "setFullYear", DateSetFullYear,
1104 "setUTCFullYear", DateSetUTCFullYear,
1105 "toGMTString", DateToGMTString,
1106 "toUTCString", DateToUTCString,
1107 "getYear", DateGetYear,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001108 "setYear", DateSetYear,
1109 "toISOString", DateToISOString,
1110 "toJSON", DateToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001111 ));
1112}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113
1114SetupDate();