blob: 1fb4897921a91fb1d434909136e9d0034f584c29 [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) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000084 return DaysInYear(YearFromTime(time)) == 366 ? 1 : 0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000085}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000086
87
88function DayWithinYear(time) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000089 return DAY(time) - DayFromYear(YearFromTime(time));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000090}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091
92
93// ECMA 262 - 15.9.1.9
94function EquivalentYear(year) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +000095 // Returns an equivalent year in the range [2008-2035] matching
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 // - leap year.
97 // - week day of first day.
98 var time = TimeFromYear(year);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000099 var recent_year = (InLeapYear(time) == 0 ? 1967 : 1956) +
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000100 (WeekDay(time) * 12) % 28;
101 // Find the year in the range 2008..2037 that is equivalent mod 28.
102 // Add 3*28 to give a positive argument to the modulus operator.
103 return 2008 + (recent_year + 3*28 - 2008) % 28;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000104}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
106
107function EquivalentTime(t) {
108 // The issue here is that some library calls don't work right for dates
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000109 // that cannot be represented using a non-negative signed 32 bit integer
110 // (measured in whole seconds based on the 1970 epoch).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111 // We solve this by mapping the time to a year with same leap-year-ness
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000112 // and same starting day for the year. The ECMAscript specification says
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000113 // we must do this, but for compatibility with other browsers, we use
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000114 // the actual year if it is in the range 1970..2037
115 if (t >= 0 && t <= 2.1e12) return t;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000116
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000117 var day = MakeDay(EquivalentYear(YearFromTime(t)),
118 MonthFromTime(t),
119 DateFromTime(t));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000120 return MakeDate(day, TimeWithinDay(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000121}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000123
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000124// local_time_offset is initialized when the DST_offset_cache is missed.
125// It must not be used until after a call to DaylightSavingsOffset().
126// In this way, only one check, for a DST cache miss, is needed.
127var local_time_offset;
128
129
130// Because computing the DST offset is an expensive operation,
131// we keep a cache of the last computed DST offset along with a time interval
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000132// where we know the cache is valid.
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000133// When the cache is valid, local_time_offset is also valid.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000134var DST_offset_cache = {
135 // Cached DST offset.
136 offset: 0,
137 // Time interval where the cached offset is valid.
138 start: 0, end: -1,
139 // Size of next interval expansion.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000140 increment: 0,
141 initial_increment: 19 * msPerDay
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000142};
143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000144
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000145// NOTE: The implementation relies on the fact that no time zones have
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000146// more than one daylight savings offset change per 19 days.
147//
148// In Egypt in 2010 they decided to suspend DST during Ramadan. This
149// led to a short interval where DST is in effect from September 10 to
150// September 30.
151//
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000152// If this function is called with NaN it returns NaN.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153function DaylightSavingsOffset(t) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000154 // Load the cache object from the builtins object.
155 var cache = DST_offset_cache;
156
157 // Cache the start and the end in local variables for fast access.
158 var start = cache.start;
159 var end = cache.end;
160
161 if (start <= t) {
162 // If the time fits in the cached interval, return the cached offset.
163 if (t <= end) return cache.offset;
164
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000165 // If the cache misses, the local_time_offset may not be initialized.
166 if (IS_UNDEFINED(local_time_offset)) {
167 local_time_offset = %DateLocalTimeOffset();
168 }
169
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000170 // Compute a possible new interval end.
171 var new_end = end + cache.increment;
172
173 if (t <= new_end) {
174 var end_offset = %DateDaylightSavingsOffset(EquivalentTime(new_end));
175 if (cache.offset == end_offset) {
176 // If the offset at the end of the new interval still matches
177 // the offset in the cache, we grow the cached time interval
178 // and return the offset.
179 cache.end = new_end;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000180 cache.increment = cache.initial_increment;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000181 return end_offset;
182 } else {
183 var offset = %DateDaylightSavingsOffset(EquivalentTime(t));
184 if (offset == end_offset) {
185 // The offset at the given time is equal to the offset at the
186 // new end of the interval, so that means that we've just skipped
187 // the point in time where the DST offset change occurred. Updated
188 // the interval to reflect this and reset the increment.
189 cache.start = t;
190 cache.end = new_end;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 cache.increment = cache.initial_increment;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000192 } else {
193 // The interval contains a DST offset change and the given time is
194 // before it. Adjust the increment to avoid a linear search for
195 // the offset change point and change the end of the interval.
196 cache.increment /= 3;
197 cache.end = t;
198 }
199 // Update the offset in the cache and return it.
200 cache.offset = offset;
201 return offset;
202 }
203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000205
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000206 // If the cache misses, the local_time_offset may not be initialized.
207 if (IS_UNDEFINED(local_time_offset)) {
208 local_time_offset = %DateLocalTimeOffset();
209 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000210 // Compute the DST offset for the time and shrink the cache interval
211 // to only contain the time. This allows fast repeated DST offset
212 // computations for the same time.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000213 var offset = %DateDaylightSavingsOffset(EquivalentTime(t));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000214 cache.offset = offset;
215 cache.start = cache.end = t;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000216 cache.increment = cache.initial_increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217 return offset;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000218}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219
220
221var timezone_cache_time = $NaN;
222var timezone_cache_timezone;
223
224function LocalTimezone(t) {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000225 if (NUMBER_IS_NAN(t)) return "";
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000226 if (t == timezone_cache_time) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227 return timezone_cache_timezone;
228 }
229 var timezone = %DateLocalTimezone(EquivalentTime(t));
230 timezone_cache_time = t;
231 timezone_cache_timezone = timezone;
232 return timezone;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000233}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234
235
236function WeekDay(time) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000237 return Modulo(DAY(time) + 4, 7);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000238}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239
240
241function LocalTime(time) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000242 if (NUMBER_IS_NAN(time)) return time;
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000243 // DaylightSavingsOffset called before local_time_offset used.
244 return time + DaylightSavingsOffset(time) + local_time_offset;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000245}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000247
248var ltcache = {
vegorov@chromium.org42841962010-10-18 11:18:59 +0000249 key: null,
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000250 val: null
251};
252
ager@chromium.org7c537e22008-10-16 08:43:32 +0000253function LocalTimeNoCheck(time) {
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000254 var ltc = ltcache;
255 if (%_ObjectEquals(time, ltc.key)) return ltc.val;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000256
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000257 // Inline the DST offset cache checks for speed.
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000258 // The cache is hit, or DaylightSavingsOffset is called,
259 // before local_time_offset is used.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000260 var cache = DST_offset_cache;
261 if (cache.start <= time && time <= cache.end) {
262 var dst_offset = cache.offset;
263 } else {
264 var dst_offset = DaylightSavingsOffset(time);
265 }
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000266 ltc.key = time;
267 return (ltc.val = time + local_time_offset + dst_offset);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000268}
269
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000270
271function UTC(time) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000272 if (NUMBER_IS_NAN(time)) return time;
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000273 // local_time_offset is needed before the call to DaylightSavingsOffset,
274 // so it may be uninitialized.
275 if (IS_UNDEFINED(local_time_offset)) {
276 local_time_offset = %DateLocalTimeOffset();
277 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000278 var tmp = time - local_time_offset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000279 return tmp - DaylightSavingsOffset(tmp);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000280}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281
282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283// ECMA 262 - 15.9.1.11
284function MakeTime(hour, min, sec, ms) {
285 if (!$isFinite(hour)) return $NaN;
286 if (!$isFinite(min)) return $NaN;
287 if (!$isFinite(sec)) return $NaN;
288 if (!$isFinite(ms)) return $NaN;
289 return TO_INTEGER(hour) * msPerHour
290 + TO_INTEGER(min) * msPerMinute
291 + TO_INTEGER(sec) * msPerSecond
292 + TO_INTEGER(ms);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000294
295
296// ECMA 262 - 15.9.1.12
297function TimeInYear(year) {
298 return DaysInYear(year) * msPerDay;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300
301
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000302var ymd_from_time_cache = [$NaN, $NaN, $NaN];
303var ymd_from_time_cached_time = $NaN;
304
305function YearFromTime(t) {
306 if (t !== ymd_from_time_cached_time) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000307 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000308 return $NaN;
309 }
310
311 %DateYMDFromTime(t, ymd_from_time_cache);
312 ymd_from_time_cached_time = t
313 }
314
315 return ymd_from_time_cache[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316}
317
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000318function MonthFromTime(t) {
319 if (t !== ymd_from_time_cached_time) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000320 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000321 return $NaN;
322 }
323 %DateYMDFromTime(t, ymd_from_time_cache);
324 ymd_from_time_cached_time = t
325 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000326
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000327 return ymd_from_time_cache[1];
328}
329
330function DateFromTime(t) {
331 if (t !== ymd_from_time_cached_time) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000332 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000333 return $NaN;
334 }
335
336 %DateYMDFromTime(t, ymd_from_time_cache);
337 ymd_from_time_cached_time = t
ager@chromium.org381abbb2009-02-25 13:23:22 +0000338 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339
340 return ymd_from_time_cache[2];
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000341}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000342
ager@chromium.org7c537e22008-10-16 08:43:32 +0000343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000344// Compute number of days given a year, month, date.
345// Note that month and date can lie outside the normal range.
346// For example:
347// MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
348// MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
349// MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
350function MakeDay(year, month, date) {
351 if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return $NaN;
352
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000353 // Convert to integer and map -0 to 0.
354 year = TO_INTEGER_MAP_MINUS_ZERO(year);
355 month = TO_INTEGER_MAP_MINUS_ZERO(month);
356 date = TO_INTEGER_MAP_MINUS_ZERO(date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000358 if (year < kMinYear || year > kMaxYear ||
359 month < kMinMonth || month > kMaxMonth ||
360 date < kMinDate || date > kMaxDate) {
361 return $NaN;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 }
363
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000364 // Now we rely on year, month and date being SMIs.
365 return %DateMakeDay(year, month, date);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000366}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367
368
369// ECMA 262 - 15.9.1.13
370function MakeDate(day, time) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000371 var time = day * msPerDay + time;
372 // Some of our runtime funtions for computing UTC(time) rely on
373 // times not being significantly larger than MAX_TIME_MS. If there
374 // is no way that the time can be within range even after UTC
375 // conversion we return NaN immediately instead of relying on
376 // TimeClip to do it.
377 if ($abs(time) > MAX_TIME_BEFORE_UTC) return $NaN;
378 return time;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000379}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380
381
382// ECMA 262 - 15.9.1.14
383function TimeClip(time) {
384 if (!$isFinite(time)) return $NaN;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000385 if ($abs(time) > MAX_TIME_MS) return $NaN;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 return TO_INTEGER(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000387}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000388
389
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000390// The Date cache is used to limit the cost of parsing the same Date
391// strings over and over again.
392var Date_cache = {
393 // Cached time value.
394 time: $NaN,
395 // Cached year when interpreting the time as a local time. Only
396 // valid when the time matches cached time.
397 year: $NaN,
398 // String input for which the cached time is valid.
399 string: null
400};
401
402
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000403%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000404 if (!%_IsConstructCall()) {
405 // ECMA 262 - 15.9.2
406 return (new $Date()).toString();
407 }
408
409 // ECMA 262 - 15.9.3
410 var argc = %_ArgumentsLength();
411 var value;
412 if (argc == 0) {
413 value = %DateCurrentTime();
414
415 } else if (argc == 1) {
416 if (IS_NUMBER(year)) {
417 value = TimeClip(year);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000418
419 } else if (IS_STRING(year)) {
420 // Probe the Date cache. If we already have a time value for the
421 // given time, we re-use that instead of parsing the string again.
422 var cache = Date_cache;
423 if (cache.string === year) {
424 value = cache.time;
425 } else {
426 value = DateParse(year);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000427 if (!NUMBER_IS_NAN(value)) {
428 cache.time = value;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000429 cache.year = YearFromTime(LocalTimeNoCheck(value));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000430 cache.string = year;
431 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000432 }
433
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000434 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435 // According to ECMA 262, no hint should be given for this
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000436 // conversion. However, ToPrimitive defaults to STRING_HINT for
437 // Date objects which will lose precision when the Date
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438 // constructor is called with another Date object as its
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000439 // argument. We therefore use NUMBER_HINT for the conversion,
440 // which is the default for everything else than Date objects.
441 // This makes us behave like KJS and SpiderMonkey.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000442 var time = ToPrimitive(year, NUMBER_HINT);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000443 value = IS_STRING(time) ? DateParse(time) : TimeClip(ToNumber(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000445
446 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000447 year = ToNumber(year);
448 month = ToNumber(month);
449 date = argc > 2 ? ToNumber(date) : 1;
450 hours = argc > 3 ? ToNumber(hours) : 0;
451 minutes = argc > 4 ? ToNumber(minutes) : 0;
452 seconds = argc > 5 ? ToNumber(seconds) : 0;
453 ms = argc > 6 ? ToNumber(ms) : 0;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000454 year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455 ? 1900 + TO_INTEGER(year) : year;
456 var day = MakeDay(year, month, date);
457 var time = MakeTime(hours, minutes, seconds, ms);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000458 value = TimeClip(UTC(MakeDate(day, time)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000460 %_SetValueOf(this, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461});
462
463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000464%FunctionSetPrototype($Date, new $Date($NaN));
465
466
467var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
468var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
469
470
471function TwoDigitString(value) {
472 return value < 10 ? "0" + value : "" + value;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000473}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474
475
476function DateString(time) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477 return WeekDays[WeekDay(time)] + ' '
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000478 + Months[MonthFromTime(time)] + ' '
479 + TwoDigitString(DateFromTime(time)) + ' '
480 + YearFromTime(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000481}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482
483
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000484var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
485var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
486
487
488function LongDateString(time) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000489 return LongWeekDays[WeekDay(time)] + ', '
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000490 + LongMonths[MonthFromTime(time)] + ' '
491 + TwoDigitString(DateFromTime(time)) + ', '
492 + YearFromTime(time);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000493}
494
495
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496function TimeString(time) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000497 return TwoDigitString(HOUR_FROM_TIME(time)) + ':'
498 + TwoDigitString(MIN_FROM_TIME(time)) + ':'
499 + TwoDigitString(SEC_FROM_TIME(time));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000500}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501
502
503function LocalTimezoneString(time) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000504 var old_timezone = timezone_cache_timezone;
505 var timezone = LocalTimezone(time);
506 if (old_timezone && timezone != old_timezone) {
507 // If the timezone string has changed from the one that we cached,
508 // the local time offset may now be wrong. So we need to update it
509 // and try again.
510 local_time_offset = %DateLocalTimeOffset();
511 // We also need to invalidate the DST cache as the new timezone may have
512 // different DST times.
513 var dst_cache = DST_offset_cache;
514 dst_cache.start = 0;
515 dst_cache.end = -1;
516 }
517
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000518 var timezoneOffset =
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000519 (DaylightSavingsOffset(time) + local_time_offset) / msPerMinute;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520 var sign = (timezoneOffset >= 0) ? 1 : -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000521 var hours = FLOOR((sign * timezoneOffset)/60);
522 var min = FLOOR((sign * timezoneOffset)%60);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000523 var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
524 TwoDigitString(hours) + TwoDigitString(min);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000525 return gmt + ' (' + timezone + ')';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000526}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527
528
529function DatePrintString(time) {
530 return DateString(time) + ' ' + TimeString(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000531}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532
533// -------------------------------------------------------------------
534
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000535// Reused output buffer. Used when parsing date strings.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000536var parse_buffer = $Array(8);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537
538// ECMA 262 - 15.9.4.2
539function DateParse(string) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 var arr = %DateParseString(ToString(string), parse_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541 if (IS_NULL(arr)) return $NaN;
542
543 var day = MakeDay(arr[0], arr[1], arr[2]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000544 var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 var date = MakeDate(day, time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000546
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000547 if (IS_NULL(arr[7])) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 return TimeClip(UTC(date));
549 } else {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000550 return TimeClip(date - arr[7] * 1000);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000552}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553
554
555// ECMA 262 - 15.9.4.3
556function DateUTC(year, month, date, hours, minutes, seconds, ms) {
557 year = ToNumber(year);
558 month = ToNumber(month);
559 var argc = %_ArgumentsLength();
560 date = argc > 2 ? ToNumber(date) : 1;
561 hours = argc > 3 ? ToNumber(hours) : 0;
562 minutes = argc > 4 ? ToNumber(minutes) : 0;
563 seconds = argc > 5 ? ToNumber(seconds) : 0;
564 ms = argc > 6 ? ToNumber(ms) : 0;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000565 year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 ? 1900 + TO_INTEGER(year) : year;
567 var day = MakeDay(year, month, date);
568 var time = MakeTime(hours, minutes, seconds, ms);
569 return %_SetValueOf(this, TimeClip(MakeDate(day, time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000570}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571
572
573// Mozilla-specific extension. Returns the number of milliseconds
574// elapsed since 1 January 1970 00:00:00 UTC.
575function DateNow() {
mads.s.ager31e71382008-08-13 09:32:07 +0000576 return %DateCurrentTime();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000577}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578
579
580// ECMA 262 - 15.9.5.2
581function DateToString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000582 var t = DATE_VALUE(this);
583 if (NUMBER_IS_NAN(t)) return kInvalidDate;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000584 var time_zone_string = LocalTimezoneString(t); // May update local offset.
585 return DatePrintString(LocalTimeNoCheck(t)) + time_zone_string;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000586}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000587
588
589// ECMA 262 - 15.9.5.3
590function DateToDateString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000591 var t = DATE_VALUE(this);
592 if (NUMBER_IS_NAN(t)) return kInvalidDate;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000593 return DateString(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000594}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595
596
597// ECMA 262 - 15.9.5.4
598function DateToTimeString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000599 var t = DATE_VALUE(this);
600 if (NUMBER_IS_NAN(t)) return kInvalidDate;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000601 var time_zone_string = LocalTimezoneString(t); // May update local offset.
602 return TimeString(LocalTimeNoCheck(t)) + time_zone_string;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000603}
604
605
606// ECMA 262 - 15.9.5.5
607function DateToLocaleString() {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000608 return %_CallFunction(this, DateToString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000609}
610
611
612// ECMA 262 - 15.9.5.6
613function DateToLocaleDateString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000614 var t = DATE_VALUE(this);
615 if (NUMBER_IS_NAN(t)) return kInvalidDate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000616 return LongDateString(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000617}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618
619
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000620// ECMA 262 - 15.9.5.7
621function DateToLocaleTimeString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000622 var t = DATE_VALUE(this);
623 if (NUMBER_IS_NAN(t)) return kInvalidDate;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000624 var lt = LocalTimeNoCheck(t);
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000625 return TimeString(lt);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000626}
627
628
629// ECMA 262 - 15.9.5.8
630function DateValueOf() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000631 return DATE_VALUE(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000632}
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000633
634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635// ECMA 262 - 15.9.5.9
636function DateGetTime() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000637 return DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638}
639
640
641// ECMA 262 - 15.9.5.10
642function DateGetFullYear() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000643 var t = DATE_VALUE(this);
644 if (NUMBER_IS_NAN(t)) return t;
645 var cache = Date_cache;
646 if (cache.time === t) return cache.year;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000647 return YearFromTime(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000648}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649
650
651// ECMA 262 - 15.9.5.11
652function DateGetUTCFullYear() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000653 var t = DATE_VALUE(this);
654 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000655 return YearFromTime(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000656}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657
658
659// ECMA 262 - 15.9.5.12
660function DateGetMonth() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000661 var t = DATE_VALUE(this);
662 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000663 return MonthFromTime(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000664}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665
666
667// ECMA 262 - 15.9.5.13
668function DateGetUTCMonth() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000669 var t = DATE_VALUE(this);
670 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000671 return MonthFromTime(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000672}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000673
674
675// ECMA 262 - 15.9.5.14
676function DateGetDate() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000677 var t = DATE_VALUE(this);
678 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000679 return DateFromTime(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000680}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681
682
683// ECMA 262 - 15.9.5.15
684function DateGetUTCDate() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000685 var t = DATE_VALUE(this);
686 return NAN_OR_DATE_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000687}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000688
689
690// ECMA 262 - 15.9.5.16
691function DateGetDay() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000692 var t = %_ValueOf(this);
693 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000694 return WeekDay(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000695}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696
697
698// ECMA 262 - 15.9.5.17
699function DateGetUTCDay() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000700 var t = %_ValueOf(this);
701 if (NUMBER_IS_NAN(t)) return t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702 return WeekDay(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000703}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704
705
706// ECMA 262 - 15.9.5.18
707function DateGetHours() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000708 var t = DATE_VALUE(this);
709 if (NUMBER_IS_NAN(t)) return t;
710 return HOUR_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000711}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712
713
714// ECMA 262 - 15.9.5.19
715function DateGetUTCHours() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000716 var t = DATE_VALUE(this);
717 if (NUMBER_IS_NAN(t)) return t;
718 return HOUR_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000719}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000720
721
722// ECMA 262 - 15.9.5.20
723function DateGetMinutes() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000724 var t = DATE_VALUE(this);
725 if (NUMBER_IS_NAN(t)) return t;
726 return MIN_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000727}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000728
729
730// ECMA 262 - 15.9.5.21
731function DateGetUTCMinutes() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000732 var t = DATE_VALUE(this);
733 return NAN_OR_MIN_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000734}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735
736
737// ECMA 262 - 15.9.5.22
738function DateGetSeconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000739 var t = DATE_VALUE(this);
740 if (NUMBER_IS_NAN(t)) return t;
741 return SEC_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000742}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743
744
745// ECMA 262 - 15.9.5.23
746function DateGetUTCSeconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000747 var t = DATE_VALUE(this);
748 return NAN_OR_SEC_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000749}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750
751
752// ECMA 262 - 15.9.5.24
753function DateGetMilliseconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000754 var t = DATE_VALUE(this);
755 if (NUMBER_IS_NAN(t)) return t;
756 return MS_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000757}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758
759
760// ECMA 262 - 15.9.5.25
761function DateGetUTCMilliseconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000762 var t = DATE_VALUE(this);
763 return NAN_OR_MS_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000764}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765
766
767// ECMA 262 - 15.9.5.26
768function DateGetTimezoneOffset() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000769 var t = DATE_VALUE(this);
770 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000771 return (t - LocalTimeNoCheck(t)) / msPerMinute;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000772}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773
774
775// ECMA 262 - 15.9.5.27
776function DateSetTime(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000777 if (!IS_DATE(this)) ThrowDateTypeError();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778 return %_SetValueOf(this, TimeClip(ToNumber(ms)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000779}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780
781
782// ECMA 262 - 15.9.5.28
783function DateSetMilliseconds(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000784 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785 ms = ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000786 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), SEC_FROM_TIME(t), ms);
787 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000788}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789
790
791// ECMA 262 - 15.9.5.29
792function DateSetUTCMilliseconds(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000793 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000794 ms = ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000795 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), SEC_FROM_TIME(t), ms);
796 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000797}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798
799
800// ECMA 262 - 15.9.5.30
801function DateSetSeconds(sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000802 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803 sec = ToNumber(sec);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000804 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000805 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
806 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000807}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808
809
810// ECMA 262 - 15.9.5.31
811function DateSetUTCSeconds(sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000812 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813 sec = ToNumber(sec);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000814 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000815 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
816 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000817}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818
819
820// ECMA 262 - 15.9.5.33
821function DateSetMinutes(min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000822 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 min = ToNumber(min);
824 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000825 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
826 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000827 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
828 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000829}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830
831
832// ECMA 262 - 15.9.5.34
833function DateSetUTCMinutes(min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000834 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835 min = ToNumber(min);
836 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000837 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
838 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000839 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
840 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000841}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842
843
844// ECMA 262 - 15.9.5.35
845function DateSetHours(hour, min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000846 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 hour = ToNumber(hour);
848 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000849 min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
850 sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
851 ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852 var time = MakeTime(hour, min, sec, ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000853 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000854}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855
856
857// ECMA 262 - 15.9.5.34
858function DateSetUTCHours(hour, min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000859 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860 hour = ToNumber(hour);
861 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000862 min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
863 sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
864 ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 var time = MakeTime(hour, min, sec, ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000866 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000867}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868
869
870// ECMA 262 - 15.9.5.36
871function DateSetDate(date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000872 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873 date = ToNumber(date);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000874 var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000875 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000876}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000877
878
879// ECMA 262 - 15.9.5.37
880function DateSetUTCDate(date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000881 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000882 date = ToNumber(date);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000883 var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000885}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886
887
888// ECMA 262 - 15.9.5.38
889function DateSetMonth(month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000890 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891 month = ToNumber(month);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000892 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000893 var day = MakeDay(YearFromTime(t), month, date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000895}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896
897
898// ECMA 262 - 15.9.5.39
899function DateSetUTCMonth(month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000900 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901 month = ToNumber(month);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000902 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000903 var day = MakeDay(YearFromTime(t), month, date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000905}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906
907
908// ECMA 262 - 15.9.5.40
909function DateSetFullYear(year, month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000910 var t = DATE_VALUE(this);
911 t = NUMBER_IS_NAN(t) ? 0 : LocalTimeNoCheck(t);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912 year = ToNumber(year);
913 var argc = %_ArgumentsLength();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000914 month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
915 date = argc < 3 ? DateFromTime(t) : ToNumber(date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 var day = MakeDay(year, month, date);
917 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000918}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919
920
921// ECMA 262 - 15.9.5.41
922function DateSetUTCFullYear(year, month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000923 var t = DATE_VALUE(this);
924 if (NUMBER_IS_NAN(t)) t = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 var argc = %_ArgumentsLength();
926 year = ToNumber(year);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000927 month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
928 date = argc < 3 ? DateFromTime(t) : ToNumber(date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000929 var day = MakeDay(year, month, date);
930 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000931}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932
933
934// ECMA 262 - 15.9.5.42
935function DateToUTCString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000936 var t = DATE_VALUE(this);
937 if (NUMBER_IS_NAN(t)) return kInvalidDate;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
939 return WeekDays[WeekDay(t)] + ', '
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000940 + TwoDigitString(DateFromTime(t)) + ' '
941 + Months[MonthFromTime(t)] + ' '
942 + YearFromTime(t) + ' '
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943 + TimeString(t) + ' GMT';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000944}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000945
946
947// ECMA 262 - B.2.4
948function DateGetYear() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000949 var t = DATE_VALUE(this);
950 if (NUMBER_IS_NAN(t)) return $NaN;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000951 return YearFromTime(LocalTimeNoCheck(t)) - 1900;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000952}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000953
954
955// ECMA 262 - B.2.5
956function DateSetYear(year) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000957 var t = LocalTime(DATE_VALUE(this));
958 if (NUMBER_IS_NAN(t)) t = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959 year = ToNumber(year);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000960 if (NUMBER_IS_NAN(year)) return %_SetValueOf(this, $NaN);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961 year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
962 ? 1900 + TO_INTEGER(year) : year;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000963 var day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000964 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000965}
966
967
968// ECMA 262 - B.2.6
969//
970// Notice that this does not follow ECMA 262 completely. ECMA 262
971// says that toGMTString should be the same Function object as
972// toUTCString. JSC does not do this, so for compatibility we do not
973// do that either. Instead, we create a new function whose name
974// property will return toGMTString.
975function DateToGMTString() {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000976 return %_CallFunction(this, DateToUTCString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000977}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000978
979
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000980function PadInt(n, digits) {
981 if (digits == 1) return n;
982 return n < MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000983}
984
985
986function DateToISOString() {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000987 var t = DATE_VALUE(this);
988 if (NUMBER_IS_NAN(t)) return kInvalidDate;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000989 return this.getUTCFullYear() +
990 '-' + PadInt(this.getUTCMonth() + 1, 2) +
991 '-' + PadInt(this.getUTCDate(), 2) +
992 'T' + PadInt(this.getUTCHours(), 2) +
993 ':' + PadInt(this.getUTCMinutes(), 2) +
994 ':' + PadInt(this.getUTCSeconds(), 2) +
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000995 '.' + PadInt(this.getUTCMilliseconds(), 3) +
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000996 'Z';
997}
998
999
1000function DateToJSON(key) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001001 var o = ToObject(this);
1002 var tv = DefaultNumber(o);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001003 if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001004 return null;
1005 }
1006 return o.toISOString();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001007}
1008
1009
whesse@chromium.org023421e2010-12-21 12:19:12 +00001010function ResetDateCache() {
1011
1012 // Reset the local_time_offset:
1013 local_time_offset = %DateLocalTimeOffset();
1014
1015 // Reset the DST offset cache:
1016 var cache = DST_offset_cache;
1017 cache.offset = 0;
1018 cache.start = 0;
1019 cache.end = -1;
1020 cache.increment = 0;
1021 cache.initial_increment = 19 * msPerDay;
1022
1023 // Reset the timezone cache:
1024 timezone_cache_time = $NaN;
1025 timezone_cache_timezone = undefined;
1026
1027 // Reset the ltcache:
1028 ltcache.key = null;
1029 ltcache.val = null;
1030
1031 // Reset the ymd_from_time_cache:
1032 ymd_from_time_cache = [$NaN, $NaN, $NaN];
1033 ymd_from_time_cached_time = $NaN;
1034
1035 // Reset the date cache:
1036 cache = Date_cache;
1037 cache.time = $NaN;
1038 cache.year = $NaN;
1039 cache.string = null;
1040}
1041
1042
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043// -------------------------------------------------------------------
1044
1045function SetupDate() {
1046 // Setup non-enumerable properties of the Date object itself.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001047 InstallFunctions($Date, DONT_ENUM, $Array(
1048 "UTC", DateUTC,
1049 "parse", DateParse,
1050 "now", DateNow
1051 ));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001053 // Setup non-enumerable constructor property of the Date prototype object.
1054 %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
1055
1056 // Setup non-enumerable functions of the Date prototype object and
1057 // set their names.
ager@chromium.org9085a012009-05-11 19:22:57 +00001058 InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001059 "toString", DateToString,
1060 "toDateString", DateToDateString,
1061 "toTimeString", DateToTimeString,
1062 "toLocaleString", DateToLocaleString,
1063 "toLocaleDateString", DateToLocaleDateString,
1064 "toLocaleTimeString", DateToLocaleTimeString,
1065 "valueOf", DateValueOf,
1066 "getTime", DateGetTime,
1067 "getFullYear", DateGetFullYear,
1068 "getUTCFullYear", DateGetUTCFullYear,
1069 "getMonth", DateGetMonth,
1070 "getUTCMonth", DateGetUTCMonth,
1071 "getDate", DateGetDate,
1072 "getUTCDate", DateGetUTCDate,
1073 "getDay", DateGetDay,
1074 "getUTCDay", DateGetUTCDay,
1075 "getHours", DateGetHours,
1076 "getUTCHours", DateGetUTCHours,
1077 "getMinutes", DateGetMinutes,
1078 "getUTCMinutes", DateGetUTCMinutes,
1079 "getSeconds", DateGetSeconds,
1080 "getUTCSeconds", DateGetUTCSeconds,
1081 "getMilliseconds", DateGetMilliseconds,
1082 "getUTCMilliseconds", DateGetUTCMilliseconds,
1083 "getTimezoneOffset", DateGetTimezoneOffset,
1084 "setTime", DateSetTime,
1085 "setMilliseconds", DateSetMilliseconds,
1086 "setUTCMilliseconds", DateSetUTCMilliseconds,
1087 "setSeconds", DateSetSeconds,
1088 "setUTCSeconds", DateSetUTCSeconds,
1089 "setMinutes", DateSetMinutes,
1090 "setUTCMinutes", DateSetUTCMinutes,
1091 "setHours", DateSetHours,
1092 "setUTCHours", DateSetUTCHours,
1093 "setDate", DateSetDate,
1094 "setUTCDate", DateSetUTCDate,
1095 "setMonth", DateSetMonth,
1096 "setUTCMonth", DateSetUTCMonth,
1097 "setFullYear", DateSetFullYear,
1098 "setUTCFullYear", DateSetUTCFullYear,
1099 "toGMTString", DateToGMTString,
1100 "toUTCString", DateToUTCString,
1101 "getYear", DateGetYear,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001102 "setYear", DateSetYear,
1103 "toISOString", DateToISOString,
1104 "toJSON", DateToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001105 ));
1106}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107
1108SetupDate();