blob: 960147072c27cca7d690fe8beba71d64dffc7ea0 [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) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000084 return DaysInYear(YEAR_FROM_TIME(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) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000089 return DAY(time) - DayFromYear(YEAR_FROM_TIME(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
117 var day = MakeDay(EquivalentYear(YEAR_FROM_TIME(t)),
118 MONTH_FROM_TIME(t),
119 DATE_FROM_TIME(t));
120 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 if (time < -MAX_TIME_MS || time > MAX_TIME_MS) {
257 return $NaN;
258 }
259
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000260 // Inline the DST offset cache checks for speed.
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000261 // The cache is hit, or DaylightSavingsOffset is called,
262 // before local_time_offset is used.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000263 var cache = DST_offset_cache;
264 if (cache.start <= time && time <= cache.end) {
265 var dst_offset = cache.offset;
266 } else {
267 var dst_offset = DaylightSavingsOffset(time);
268 }
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000269 ltc.key = time;
270 return (ltc.val = time + local_time_offset + dst_offset);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000271}
272
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273
274function UTC(time) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000275 if (NUMBER_IS_NAN(time)) return time;
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000276 // local_time_offset is needed before the call to DaylightSavingsOffset,
277 // so it may be uninitialized.
278 if (IS_UNDEFINED(local_time_offset)) {
279 local_time_offset = %DateLocalTimeOffset();
280 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000281 var tmp = time - local_time_offset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282 return tmp - DaylightSavingsOffset(tmp);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000283}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284
285
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286// ECMA 262 - 15.9.1.11
287function MakeTime(hour, min, sec, ms) {
288 if (!$isFinite(hour)) return $NaN;
289 if (!$isFinite(min)) return $NaN;
290 if (!$isFinite(sec)) return $NaN;
291 if (!$isFinite(ms)) return $NaN;
292 return TO_INTEGER(hour) * msPerHour
293 + TO_INTEGER(min) * msPerMinute
294 + TO_INTEGER(sec) * msPerSecond
295 + TO_INTEGER(ms);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297
298
299// ECMA 262 - 15.9.1.12
300function TimeInYear(year) {
301 return DaysInYear(year) * msPerDay;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000302}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000303
304
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000305var ymd_from_time_cache = [$NaN, $NaN, $NaN];
306var ymd_from_time_cached_time = $NaN;
307
308function YearFromTime(t) {
309 if (t !== ymd_from_time_cached_time) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000310 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311 return $NaN;
312 }
313
314 %DateYMDFromTime(t, ymd_from_time_cache);
315 ymd_from_time_cached_time = t
316 }
317
318 return ymd_from_time_cache[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319}
320
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000321function MonthFromTime(t) {
322 if (t !== ymd_from_time_cached_time) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000323 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000324 return $NaN;
325 }
326 %DateYMDFromTime(t, ymd_from_time_cache);
327 ymd_from_time_cached_time = t
328 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000329
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000330 return ymd_from_time_cache[1];
331}
332
333function DateFromTime(t) {
334 if (t !== ymd_from_time_cached_time) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000335 if (!$isFinite(t)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000336 return $NaN;
337 }
338
339 %DateYMDFromTime(t, ymd_from_time_cache);
340 ymd_from_time_cached_time = t
ager@chromium.org381abbb2009-02-25 13:23:22 +0000341 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000342
343 return ymd_from_time_cache[2];
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000344}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
ager@chromium.org7c537e22008-10-16 08:43:32 +0000346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347// Compute number of days given a year, month, date.
348// Note that month and date can lie outside the normal range.
349// For example:
350// MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
351// MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
352// MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
353function MakeDay(year, month, date) {
354 if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return $NaN;
355
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000356 // Convert to integer and map -0 to 0.
357 year = TO_INTEGER_MAP_MINUS_ZERO(year);
358 month = TO_INTEGER_MAP_MINUS_ZERO(month);
359 date = TO_INTEGER_MAP_MINUS_ZERO(date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000361 if (year < kMinYear || year > kMaxYear ||
362 month < kMinMonth || month > kMaxMonth ||
363 date < kMinDate || date > kMaxDate) {
364 return $NaN;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 }
366
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000367 // Now we rely on year, month and date being SMIs.
368 return %DateMakeDay(year, month, date);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000369}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370
371
372// ECMA 262 - 15.9.1.13
373function MakeDate(day, time) {
374 if (!$isFinite(day)) return $NaN;
375 if (!$isFinite(time)) return $NaN;
376 return day * msPerDay + time;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000377}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378
379
380// ECMA 262 - 15.9.1.14
381function TimeClip(time) {
382 if (!$isFinite(time)) return $NaN;
383 if ($abs(time) > 8.64E15) return $NaN;
384 return TO_INTEGER(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000385}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386
387
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000388// The Date cache is used to limit the cost of parsing the same Date
389// strings over and over again.
390var Date_cache = {
391 // Cached time value.
392 time: $NaN,
393 // Cached year when interpreting the time as a local time. Only
394 // valid when the time matches cached time.
395 year: $NaN,
396 // String input for which the cached time is valid.
397 string: null
398};
399
400
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000402 if (!%_IsConstructCall()) {
403 // ECMA 262 - 15.9.2
404 return (new $Date()).toString();
405 }
406
407 // ECMA 262 - 15.9.3
408 var argc = %_ArgumentsLength();
409 var value;
410 if (argc == 0) {
411 value = %DateCurrentTime();
412
413 } else if (argc == 1) {
414 if (IS_NUMBER(year)) {
415 value = TimeClip(year);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000416
417 } else if (IS_STRING(year)) {
418 // Probe the Date cache. If we already have a time value for the
419 // given time, we re-use that instead of parsing the string again.
420 var cache = Date_cache;
421 if (cache.string === year) {
422 value = cache.time;
423 } else {
424 value = DateParse(year);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000425 if (!NUMBER_IS_NAN(value)) {
426 cache.time = value;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000427 cache.year = YEAR_FROM_TIME(LocalTimeNoCheck(value));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000428 cache.string = year;
429 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000430 }
431
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000432 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000433 // According to ECMA 262, no hint should be given for this
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000434 // conversion. However, ToPrimitive defaults to STRING_HINT for
435 // Date objects which will lose precision when the Date
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436 // constructor is called with another Date object as its
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000437 // argument. We therefore use NUMBER_HINT for the conversion,
438 // which is the default for everything else than Date objects.
439 // This makes us behave like KJS and SpiderMonkey.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440 var time = ToPrimitive(year, NUMBER_HINT);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000441 value = IS_STRING(time) ? DateParse(time) : TimeClip(ToNumber(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000442 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000443
444 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445 year = ToNumber(year);
446 month = ToNumber(month);
447 date = argc > 2 ? ToNumber(date) : 1;
448 hours = argc > 3 ? ToNumber(hours) : 0;
449 minutes = argc > 4 ? ToNumber(minutes) : 0;
450 seconds = argc > 5 ? ToNumber(seconds) : 0;
451 ms = argc > 6 ? ToNumber(ms) : 0;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000452 year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453 ? 1900 + TO_INTEGER(year) : year;
454 var day = MakeDay(year, month, date);
455 var time = MakeTime(hours, minutes, seconds, ms);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000456 value = TimeClip(UTC(MakeDate(day, time)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000457 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000458 %_SetValueOf(this, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459});
460
461
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462%FunctionSetPrototype($Date, new $Date($NaN));
463
464
465var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
466var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
467
468
469function TwoDigitString(value) {
470 return value < 10 ? "0" + value : "" + value;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000471}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472
473
474function DateString(time) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475 return WeekDays[WeekDay(time)] + ' '
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 + Months[MonthFromTime(time)] + ' '
477 + TwoDigitString(DateFromTime(time)) + ' '
478 + YearFromTime(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000479}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000480
481
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000482var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
483var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
484
485
486function LongDateString(time) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000487 return LongWeekDays[WeekDay(time)] + ', '
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000488 + LongMonths[MonthFromTime(time)] + ' '
489 + TwoDigitString(DateFromTime(time)) + ', '
490 + YearFromTime(time);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000491}
492
493
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494function TimeString(time) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000495 return TwoDigitString(HOUR_FROM_TIME(time)) + ':'
496 + TwoDigitString(MIN_FROM_TIME(time)) + ':'
497 + TwoDigitString(SEC_FROM_TIME(time));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000498}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000499
500
501function LocalTimezoneString(time) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000502 var old_timezone = timezone_cache_timezone;
503 var timezone = LocalTimezone(time);
504 if (old_timezone && timezone != old_timezone) {
505 // If the timezone string has changed from the one that we cached,
506 // the local time offset may now be wrong. So we need to update it
507 // and try again.
508 local_time_offset = %DateLocalTimeOffset();
509 // We also need to invalidate the DST cache as the new timezone may have
510 // different DST times.
511 var dst_cache = DST_offset_cache;
512 dst_cache.start = 0;
513 dst_cache.end = -1;
514 }
515
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000516 var timezoneOffset =
whesse@chromium.org421a0f42010-03-30 15:09:23 +0000517 (DaylightSavingsOffset(time) + local_time_offset) / msPerMinute;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518 var sign = (timezoneOffset >= 0) ? 1 : -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000519 var hours = FLOOR((sign * timezoneOffset)/60);
520 var min = FLOOR((sign * timezoneOffset)%60);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000521 var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
522 TwoDigitString(hours) + TwoDigitString(min);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000523 return gmt + ' (' + timezone + ')';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000524}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525
526
527function DatePrintString(time) {
528 return DateString(time) + ' ' + TimeString(time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000529}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530
531// -------------------------------------------------------------------
532
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000533// Reused output buffer. Used when parsing date strings.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000534var parse_buffer = $Array(8);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535
536// ECMA 262 - 15.9.4.2
537function DateParse(string) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000538 var arr = %DateParseString(ToString(string), parse_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539 if (IS_NULL(arr)) return $NaN;
540
541 var day = MakeDay(arr[0], arr[1], arr[2]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000542 var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543 var date = MakeDate(day, time);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000544
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000545 if (IS_NULL(arr[7])) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546 return TimeClip(UTC(date));
547 } else {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000548 return TimeClip(date - arr[7] * 1000);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000550}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551
552
553// ECMA 262 - 15.9.4.3
554function DateUTC(year, month, date, hours, minutes, seconds, ms) {
555 year = ToNumber(year);
556 month = ToNumber(month);
557 var argc = %_ArgumentsLength();
558 date = argc > 2 ? ToNumber(date) : 1;
559 hours = argc > 3 ? ToNumber(hours) : 0;
560 minutes = argc > 4 ? ToNumber(minutes) : 0;
561 seconds = argc > 5 ? ToNumber(seconds) : 0;
562 ms = argc > 6 ? ToNumber(ms) : 0;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000563 year = (!NUMBER_IS_NAN(year) && 0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000564 ? 1900 + TO_INTEGER(year) : year;
565 var day = MakeDay(year, month, date);
566 var time = MakeTime(hours, minutes, seconds, ms);
567 return %_SetValueOf(this, TimeClip(MakeDate(day, time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000568}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569
570
571// Mozilla-specific extension. Returns the number of milliseconds
572// elapsed since 1 January 1970 00:00:00 UTC.
573function DateNow() {
mads.s.ager31e71382008-08-13 09:32:07 +0000574 return %DateCurrentTime();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000575}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576
577
578// ECMA 262 - 15.9.5.2
579function DateToString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000580 var t = DATE_VALUE(this);
581 if (NUMBER_IS_NAN(t)) return kInvalidDate;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000582 var time_zone_string = LocalTimezoneString(t); // May update local offset.
583 return DatePrintString(LocalTimeNoCheck(t)) + time_zone_string;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000584}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585
586
587// ECMA 262 - 15.9.5.3
588function DateToDateString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000589 var t = DATE_VALUE(this);
590 if (NUMBER_IS_NAN(t)) return kInvalidDate;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000591 return DateString(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000592}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000593
594
595// ECMA 262 - 15.9.5.4
596function DateToTimeString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000597 var t = DATE_VALUE(this);
598 if (NUMBER_IS_NAN(t)) return kInvalidDate;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000599 var time_zone_string = LocalTimezoneString(t); // May update local offset.
600 return TimeString(LocalTimeNoCheck(t)) + time_zone_string;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000601}
602
603
604// ECMA 262 - 15.9.5.5
605function DateToLocaleString() {
606 return DateToString.call(this);
607}
608
609
610// ECMA 262 - 15.9.5.6
611function DateToLocaleDateString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000612 var t = DATE_VALUE(this);
613 if (NUMBER_IS_NAN(t)) return kInvalidDate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000614 return LongDateString(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000615}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616
617
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000618// ECMA 262 - 15.9.5.7
619function DateToLocaleTimeString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000620 var t = DATE_VALUE(this);
621 if (NUMBER_IS_NAN(t)) return kInvalidDate;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000622 var lt = LocalTimeNoCheck(t);
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000623 return TimeString(lt);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000624}
625
626
627// ECMA 262 - 15.9.5.8
628function DateValueOf() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000629 return DATE_VALUE(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000630}
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000631
632
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633// ECMA 262 - 15.9.5.9
634function DateGetTime() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000635 return DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636}
637
638
639// ECMA 262 - 15.9.5.10
640function DateGetFullYear() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000641 var t = DATE_VALUE(this);
642 if (NUMBER_IS_NAN(t)) return t;
643 var cache = Date_cache;
644 if (cache.time === t) return cache.year;
645 return YEAR_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000646}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647
648
649// ECMA 262 - 15.9.5.11
650function DateGetUTCFullYear() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000651 var t = DATE_VALUE(this);
652 if (NUMBER_IS_NAN(t)) return t;
653 return YEAR_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000654}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655
656
657// ECMA 262 - 15.9.5.12
658function DateGetMonth() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000659 var t = DATE_VALUE(this);
660 if (NUMBER_IS_NAN(t)) return t;
661 return MONTH_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000662}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663
664
665// ECMA 262 - 15.9.5.13
666function DateGetUTCMonth() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000667 var t = DATE_VALUE(this);
668 if (NUMBER_IS_NAN(t)) return t;
669 return MONTH_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000670}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671
672
673// ECMA 262 - 15.9.5.14
674function DateGetDate() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000675 var t = DATE_VALUE(this);
676 if (NUMBER_IS_NAN(t)) return t;
677 return DATE_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000678}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679
680
681// ECMA 262 - 15.9.5.15
682function DateGetUTCDate() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000683 var t = DATE_VALUE(this);
684 return NAN_OR_DATE_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000685}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686
687
688// ECMA 262 - 15.9.5.16
689function DateGetDay() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000690 var t = %_ValueOf(this);
691 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000692 return WeekDay(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000693}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694
695
696// ECMA 262 - 15.9.5.17
697function DateGetUTCDay() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000698 var t = %_ValueOf(this);
699 if (NUMBER_IS_NAN(t)) return t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700 return WeekDay(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000701}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702
703
704// ECMA 262 - 15.9.5.18
705function DateGetHours() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000706 var t = DATE_VALUE(this);
707 if (NUMBER_IS_NAN(t)) return t;
708 return HOUR_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000709}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000710
711
712// ECMA 262 - 15.9.5.19
713function DateGetUTCHours() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000714 var t = DATE_VALUE(this);
715 if (NUMBER_IS_NAN(t)) return t;
716 return HOUR_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000717}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718
719
720// ECMA 262 - 15.9.5.20
721function DateGetMinutes() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000722 var t = DATE_VALUE(this);
723 if (NUMBER_IS_NAN(t)) return t;
724 return MIN_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000725}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000726
727
728// ECMA 262 - 15.9.5.21
729function DateGetUTCMinutes() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000730 var t = DATE_VALUE(this);
731 return NAN_OR_MIN_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000732}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000733
734
735// ECMA 262 - 15.9.5.22
736function DateGetSeconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000737 var t = DATE_VALUE(this);
738 if (NUMBER_IS_NAN(t)) return t;
739 return SEC_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000740}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741
742
743// ECMA 262 - 15.9.5.23
744function DateGetUTCSeconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000745 var t = DATE_VALUE(this);
746 return NAN_OR_SEC_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000747}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000748
749
750// ECMA 262 - 15.9.5.24
751function DateGetMilliseconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000752 var t = DATE_VALUE(this);
753 if (NUMBER_IS_NAN(t)) return t;
754 return MS_FROM_TIME(LocalTimeNoCheck(t));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000755}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756
757
758// ECMA 262 - 15.9.5.25
759function DateGetUTCMilliseconds() {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000760 var t = DATE_VALUE(this);
761 return NAN_OR_MS_FROM_TIME(t);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000762}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000763
764
765// ECMA 262 - 15.9.5.26
766function DateGetTimezoneOffset() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000767 var t = DATE_VALUE(this);
768 if (NUMBER_IS_NAN(t)) return t;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000769 return (t - LocalTimeNoCheck(t)) / msPerMinute;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000770}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771
772
773// ECMA 262 - 15.9.5.27
774function DateSetTime(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000775 if (!IS_DATE(this)) ThrowDateTypeError();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776 return %_SetValueOf(this, TimeClip(ToNumber(ms)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000777}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778
779
780// ECMA 262 - 15.9.5.28
781function DateSetMilliseconds(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000782 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783 ms = ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000784 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), SEC_FROM_TIME(t), ms);
785 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000786}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787
788
789// ECMA 262 - 15.9.5.29
790function DateSetUTCMilliseconds(ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000791 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000792 ms = ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000793 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), SEC_FROM_TIME(t), ms);
794 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000795}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796
797
798// ECMA 262 - 15.9.5.30
799function DateSetSeconds(sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000800 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801 sec = ToNumber(sec);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000802 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000803 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
804 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000805}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806
807
808// ECMA 262 - 15.9.5.31
809function DateSetUTCSeconds(sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000810 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 sec = ToNumber(sec);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000812 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000813 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
814 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000815}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000816
817
818// ECMA 262 - 15.9.5.33
819function DateSetMinutes(min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000820 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000821 min = ToNumber(min);
822 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000823 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
824 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000825 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
826 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000827}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828
829
830// ECMA 262 - 15.9.5.34
831function DateSetUTCMinutes(min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000832 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000833 min = ToNumber(min);
834 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000835 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
836 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000837 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
838 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000839}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840
841
842// ECMA 262 - 15.9.5.35
843function DateSetHours(hour, min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000844 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 hour = ToNumber(hour);
846 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000847 min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
848 sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
849 ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 var time = MakeTime(hour, min, sec, ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000851 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000852}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853
854
855// ECMA 262 - 15.9.5.34
856function DateSetUTCHours(hour, min, sec, ms) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000857 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858 hour = ToNumber(hour);
859 var argc = %_ArgumentsLength();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000860 min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
861 sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
862 ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 var time = MakeTime(hour, min, sec, ms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000864 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000865}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866
867
868// ECMA 262 - 15.9.5.36
869function DateSetDate(date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000870 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 date = ToNumber(date);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000872 var day = MakeDay(YEAR_FROM_TIME(t), MONTH_FROM_TIME(t), date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000874}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000875
876
877// ECMA 262 - 15.9.5.37
878function DateSetUTCDate(date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000879 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 date = ToNumber(date);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000881 var day = MakeDay(YEAR_FROM_TIME(t), MONTH_FROM_TIME(t), date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000882 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000883}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884
885
886// ECMA 262 - 15.9.5.38
887function DateSetMonth(month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000888 var t = LocalTime(DATE_VALUE(this));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 month = ToNumber(month);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000890 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000891 var day = MakeDay(YEAR_FROM_TIME(t), month, date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000893}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894
895
896// ECMA 262 - 15.9.5.39
897function DateSetUTCMonth(month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000898 var t = DATE_VALUE(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 month = ToNumber(month);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +0000900 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901 var day = MakeDay(YEAR_FROM_TIME(t), month, date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000903}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904
905
906// ECMA 262 - 15.9.5.40
907function DateSetFullYear(year, month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000908 var t = DATE_VALUE(this);
909 t = NUMBER_IS_NAN(t) ? 0 : LocalTimeNoCheck(t);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910 year = ToNumber(year);
911 var argc = %_ArgumentsLength();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000912 month = argc < 2 ? MONTH_FROM_TIME(t) : ToNumber(month);
913 date = argc < 3 ? DATE_FROM_TIME(t) : ToNumber(date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 var day = MakeDay(year, month, date);
915 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000916}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917
918
919// ECMA 262 - 15.9.5.41
920function DateSetUTCFullYear(year, month, date) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000921 var t = DATE_VALUE(this);
922 if (NUMBER_IS_NAN(t)) t = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 var argc = %_ArgumentsLength();
924 year = ToNumber(year);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000925 month = argc < 2 ? MONTH_FROM_TIME(t) : ToNumber(month);
926 date = argc < 3 ? DATE_FROM_TIME(t) : ToNumber(date);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927 var day = MakeDay(year, month, date);
928 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000929}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930
931
932// ECMA 262 - 15.9.5.42
933function DateToUTCString() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000934 var t = DATE_VALUE(this);
935 if (NUMBER_IS_NAN(t)) return kInvalidDate;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000936 // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
937 return WeekDays[WeekDay(t)] + ', '
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000938 + TwoDigitString(DATE_FROM_TIME(t)) + ' '
939 + Months[MONTH_FROM_TIME(t)] + ' '
940 + YEAR_FROM_TIME(t) + ' '
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000941 + TimeString(t) + ' GMT';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000942}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943
944
945// ECMA 262 - B.2.4
946function DateGetYear() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000947 var t = DATE_VALUE(this);
948 if (NUMBER_IS_NAN(t)) return $NaN;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000949 return YEAR_FROM_TIME(LocalTimeNoCheck(t)) - 1900;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000950}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000951
952
953// ECMA 262 - B.2.5
954function DateSetYear(year) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000955 var t = LocalTime(DATE_VALUE(this));
956 if (NUMBER_IS_NAN(t)) t = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 year = ToNumber(year);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000958 if (NUMBER_IS_NAN(year)) return %_SetValueOf(this, $NaN);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959 year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
960 ? 1900 + TO_INTEGER(year) : year;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000961 var day = MakeDay(year, MONTH_FROM_TIME(t), DATE_FROM_TIME(t));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000963}
964
965
966// ECMA 262 - B.2.6
967//
968// Notice that this does not follow ECMA 262 completely. ECMA 262
969// says that toGMTString should be the same Function object as
970// toUTCString. JSC does not do this, so for compatibility we do not
971// do that either. Instead, we create a new function whose name
972// property will return toGMTString.
973function DateToGMTString() {
974 return DateToUTCString.call(this);
975}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976
977
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000978function PadInt(n, digits) {
979 if (digits == 1) return n;
980 return n < MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000981}
982
983
984function DateToISOString() {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000985 var t = DATE_VALUE(this);
986 if (NUMBER_IS_NAN(t)) return kInvalidDate;
987 return this.getUTCFullYear() + '-' + PadInt(this.getUTCMonth() + 1, 2) +
988 '-' + PadInt(this.getUTCDate(), 2) + 'T' + PadInt(this.getUTCHours(), 2) +
989 ':' + PadInt(this.getUTCMinutes(), 2) + ':' + PadInt(this.getUTCSeconds(), 2) +
990 '.' + PadInt(this.getUTCMilliseconds(), 3) +
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000991 'Z';
992}
993
994
995function DateToJSON(key) {
996 return CheckJSONPrimitive(this.toISOString());
997}
998
999
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001000// -------------------------------------------------------------------
1001
1002function SetupDate() {
1003 // Setup non-enumerable properties of the Date object itself.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001004 InstallFunctions($Date, DONT_ENUM, $Array(
1005 "UTC", DateUTC,
1006 "parse", DateParse,
1007 "now", DateNow
1008 ));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001010 // Setup non-enumerable constructor property of the Date prototype object.
1011 %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
1012
1013 // Setup non-enumerable functions of the Date prototype object and
1014 // set their names.
ager@chromium.org9085a012009-05-11 19:22:57 +00001015 InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001016 "toString", DateToString,
1017 "toDateString", DateToDateString,
1018 "toTimeString", DateToTimeString,
1019 "toLocaleString", DateToLocaleString,
1020 "toLocaleDateString", DateToLocaleDateString,
1021 "toLocaleTimeString", DateToLocaleTimeString,
1022 "valueOf", DateValueOf,
1023 "getTime", DateGetTime,
1024 "getFullYear", DateGetFullYear,
1025 "getUTCFullYear", DateGetUTCFullYear,
1026 "getMonth", DateGetMonth,
1027 "getUTCMonth", DateGetUTCMonth,
1028 "getDate", DateGetDate,
1029 "getUTCDate", DateGetUTCDate,
1030 "getDay", DateGetDay,
1031 "getUTCDay", DateGetUTCDay,
1032 "getHours", DateGetHours,
1033 "getUTCHours", DateGetUTCHours,
1034 "getMinutes", DateGetMinutes,
1035 "getUTCMinutes", DateGetUTCMinutes,
1036 "getSeconds", DateGetSeconds,
1037 "getUTCSeconds", DateGetUTCSeconds,
1038 "getMilliseconds", DateGetMilliseconds,
1039 "getUTCMilliseconds", DateGetUTCMilliseconds,
1040 "getTimezoneOffset", DateGetTimezoneOffset,
1041 "setTime", DateSetTime,
1042 "setMilliseconds", DateSetMilliseconds,
1043 "setUTCMilliseconds", DateSetUTCMilliseconds,
1044 "setSeconds", DateSetSeconds,
1045 "setUTCSeconds", DateSetUTCSeconds,
1046 "setMinutes", DateSetMinutes,
1047 "setUTCMinutes", DateSetUTCMinutes,
1048 "setHours", DateSetHours,
1049 "setUTCHours", DateSetUTCHours,
1050 "setDate", DateSetDate,
1051 "setUTCDate", DateSetUTCDate,
1052 "setMonth", DateSetMonth,
1053 "setUTCMonth", DateSetUTCMonth,
1054 "setFullYear", DateSetFullYear,
1055 "setUTCFullYear", DateSetUTCFullYear,
1056 "toGMTString", DateToGMTString,
1057 "toUTCString", DateToUTCString,
1058 "getYear", DateGetYear,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001059 "setYear", DateSetYear,
1060 "toISOString", DateToISOString,
1061 "toJSON", DateToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001062 ));
1063}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064
1065SetupDate();