blob: 999009e8639089bef4ef59493ebda191d2d29ebb [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29// This file relies on the fact that the following declarations have been made
30// in v8natives.js:
31// const $isFinite = GlobalIsFinite;
32
33// -------------------------------------------------------------------
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;
42
43// Helper function to throw error.
44function ThrowDateTypeError() {
45 throw new $TypeError('this is not a Date object.');
46}
47
48// ECMA 262 - 5.2
49function Modulo(value, remainder) {
50 var mod = value % remainder;
51 // Guard against returning -0.
52 if (mod == 0) return 0;
53 return mod >= 0 ? mod : mod + remainder;
54}
55
56
57function TimeWithinDay(time) {
58 return Modulo(time, msPerDay);
59}
60
61
62// ECMA 262 - 15.9.1.3
63function DaysInYear(year) {
64 if (year % 4 != 0) return 365;
65 if ((year % 100 == 0) && (year % 400 != 0)) return 365;
66 return 366;
67}
68
69
70function DayFromYear(year) {
71 return 365 * (year-1970)
72 + FLOOR((year-1969)/4)
73 - FLOOR((year-1901)/100)
74 + FLOOR((year-1601)/400);
75}
76
77
78function TimeFromYear(year) {
79 return msPerDay * DayFromYear(year);
80}
81
82
83function InLeapYear(time) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010084 return DaysInYear(YearFromTime(time)) - 365; // Returns 1 or 0.
Andrei Popescu31002712010-02-23 13:46:05 +000085}
86
87
88// ECMA 262 - 15.9.1.9
89function EquivalentYear(year) {
90 // Returns an equivalent year in the range [2008-2035] matching
91 // - leap year.
92 // - week day of first day.
93 var time = TimeFromYear(year);
94 var recent_year = (InLeapYear(time) == 0 ? 1967 : 1956) +
95 (WeekDay(time) * 12) % 28;
96 // Find the year in the range 2008..2037 that is equivalent mod 28.
97 // Add 3*28 to give a positive argument to the modulus operator.
98 return 2008 + (recent_year + 3*28 - 2008) % 28;
99}
100
101
102function EquivalentTime(t) {
103 // The issue here is that some library calls don't work right for dates
104 // that cannot be represented using a non-negative signed 32 bit integer
105 // (measured in whole seconds based on the 1970 epoch).
106 // We solve this by mapping the time to a year with same leap-year-ness
107 // and same starting day for the year. The ECMAscript specification says
108 // we must do this, but for compatibility with other browsers, we use
109 // the actual year if it is in the range 1970..2037
110 if (t >= 0 && t <= 2.1e12) return t;
Steve Block6ded16b2010-05-10 14:33:55 +0100111
Ben Murdochb0fe1622011-05-05 13:52:32 +0100112 var day = MakeDay(EquivalentYear(YearFromTime(t)),
113 MonthFromTime(t),
114 DateFromTime(t));
Steve Block6ded16b2010-05-10 14:33:55 +0100115 return MakeDate(day, TimeWithinDay(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000116}
117
118
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100119// local_time_offset is initialized when the DST_offset_cache is missed.
120// It must not be used until after a call to DaylightSavingsOffset().
121// In this way, only one check, for a DST cache miss, is needed.
122var local_time_offset;
123
124
125// Because computing the DST offset is an expensive operation,
126// we keep a cache of the last computed DST offset along with a time interval
Andrei Popescu31002712010-02-23 13:46:05 +0000127// where we know the cache is valid.
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100128// When the cache is valid, local_time_offset is also valid.
Andrei Popescu31002712010-02-23 13:46:05 +0000129var DST_offset_cache = {
130 // Cached DST offset.
131 offset: 0,
132 // Time interval where the cached offset is valid.
133 start: 0, end: -1,
134 // Size of next interval expansion.
Iain Merrick75681382010-08-19 15:07:18 +0100135 increment: 0,
136 initial_increment: 19 * msPerDay
Andrei Popescu31002712010-02-23 13:46:05 +0000137};
138
139
140// NOTE: The implementation relies on the fact that no time zones have
Iain Merrick75681382010-08-19 15:07:18 +0100141// more than one daylight savings offset change per 19 days.
142//
143// In Egypt in 2010 they decided to suspend DST during Ramadan. This
144// led to a short interval where DST is in effect from September 10 to
145// September 30.
146//
Andrei Popescu31002712010-02-23 13:46:05 +0000147// If this function is called with NaN it returns NaN.
148function DaylightSavingsOffset(t) {
149 // Load the cache object from the builtins object.
150 var cache = DST_offset_cache;
151
152 // Cache the start and the end in local variables for fast access.
153 var start = cache.start;
154 var end = cache.end;
155
156 if (start <= t) {
157 // If the time fits in the cached interval, return the cached offset.
158 if (t <= end) return cache.offset;
159
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100160 // If the cache misses, the local_time_offset may not be initialized.
161 if (IS_UNDEFINED(local_time_offset)) {
162 local_time_offset = %DateLocalTimeOffset();
163 }
164
Andrei Popescu31002712010-02-23 13:46:05 +0000165 // Compute a possible new interval end.
166 var new_end = end + cache.increment;
167
168 if (t <= new_end) {
169 var end_offset = %DateDaylightSavingsOffset(EquivalentTime(new_end));
170 if (cache.offset == end_offset) {
171 // If the offset at the end of the new interval still matches
172 // the offset in the cache, we grow the cached time interval
173 // and return the offset.
174 cache.end = new_end;
Iain Merrick75681382010-08-19 15:07:18 +0100175 cache.increment = cache.initial_increment;
Andrei Popescu31002712010-02-23 13:46:05 +0000176 return end_offset;
177 } else {
178 var offset = %DateDaylightSavingsOffset(EquivalentTime(t));
179 if (offset == end_offset) {
180 // The offset at the given time is equal to the offset at the
181 // new end of the interval, so that means that we've just skipped
182 // the point in time where the DST offset change occurred. Updated
183 // the interval to reflect this and reset the increment.
184 cache.start = t;
185 cache.end = new_end;
Iain Merrick75681382010-08-19 15:07:18 +0100186 cache.increment = cache.initial_increment;
Andrei Popescu31002712010-02-23 13:46:05 +0000187 } else {
188 // The interval contains a DST offset change and the given time is
189 // before it. Adjust the increment to avoid a linear search for
190 // the offset change point and change the end of the interval.
191 cache.increment /= 3;
192 cache.end = t;
193 }
194 // Update the offset in the cache and return it.
195 cache.offset = offset;
196 return offset;
197 }
198 }
199 }
200
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100201 // If the cache misses, the local_time_offset may not be initialized.
202 if (IS_UNDEFINED(local_time_offset)) {
203 local_time_offset = %DateLocalTimeOffset();
204 }
Andrei Popescu31002712010-02-23 13:46:05 +0000205 // Compute the DST offset for the time and shrink the cache interval
206 // to only contain the time. This allows fast repeated DST offset
207 // computations for the same time.
208 var offset = %DateDaylightSavingsOffset(EquivalentTime(t));
209 cache.offset = offset;
210 cache.start = cache.end = t;
Iain Merrick75681382010-08-19 15:07:18 +0100211 cache.increment = cache.initial_increment;
Andrei Popescu31002712010-02-23 13:46:05 +0000212 return offset;
213}
214
215
216var timezone_cache_time = $NaN;
217var timezone_cache_timezone;
218
219function LocalTimezone(t) {
220 if (NUMBER_IS_NAN(t)) return "";
221 if (t == timezone_cache_time) {
222 return timezone_cache_timezone;
223 }
224 var timezone = %DateLocalTimezone(EquivalentTime(t));
225 timezone_cache_time = t;
226 timezone_cache_timezone = timezone;
227 return timezone;
228}
229
230
231function WeekDay(time) {
232 return Modulo(DAY(time) + 4, 7);
233}
234
Andrei Popescu31002712010-02-23 13:46:05 +0000235
236function LocalTime(time) {
237 if (NUMBER_IS_NAN(time)) return time;
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100238 // DaylightSavingsOffset called before local_time_offset used.
239 return time + DaylightSavingsOffset(time) + local_time_offset;
Andrei Popescu31002712010-02-23 13:46:05 +0000240}
241
Kristian Monsen25f61362010-05-21 11:50:48 +0100242
243var ltcache = {
Ben Murdochf87a2032010-10-22 12:50:53 +0100244 key: null,
Kristian Monsen25f61362010-05-21 11:50:48 +0100245 val: null
246};
247
Andrei Popescu31002712010-02-23 13:46:05 +0000248function LocalTimeNoCheck(time) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100249 var ltc = ltcache;
250 if (%_ObjectEquals(time, ltc.key)) return ltc.val;
Steve Block6ded16b2010-05-10 14:33:55 +0100251
Andrei Popescu31002712010-02-23 13:46:05 +0000252 // Inline the DST offset cache checks for speed.
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100253 // The cache is hit, or DaylightSavingsOffset is called,
254 // before local_time_offset is used.
Andrei Popescu31002712010-02-23 13:46:05 +0000255 var cache = DST_offset_cache;
256 if (cache.start <= time && time <= cache.end) {
257 var dst_offset = cache.offset;
258 } else {
259 var dst_offset = DaylightSavingsOffset(time);
260 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100261 ltc.key = time;
262 return (ltc.val = time + local_time_offset + dst_offset);
Andrei Popescu31002712010-02-23 13:46:05 +0000263}
264
265
266function UTC(time) {
267 if (NUMBER_IS_NAN(time)) return time;
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100268 // local_time_offset is needed before the call to DaylightSavingsOffset,
269 // so it may be uninitialized.
270 if (IS_UNDEFINED(local_time_offset)) {
271 local_time_offset = %DateLocalTimeOffset();
272 }
Andrei Popescu31002712010-02-23 13:46:05 +0000273 var tmp = time - local_time_offset;
274 return tmp - DaylightSavingsOffset(tmp);
275}
276
277
278// ECMA 262 - 15.9.1.11
279function MakeTime(hour, min, sec, ms) {
280 if (!$isFinite(hour)) return $NaN;
281 if (!$isFinite(min)) return $NaN;
282 if (!$isFinite(sec)) return $NaN;
283 if (!$isFinite(ms)) return $NaN;
284 return TO_INTEGER(hour) * msPerHour
285 + TO_INTEGER(min) * msPerMinute
286 + TO_INTEGER(sec) * msPerSecond
287 + TO_INTEGER(ms);
288}
289
290
291// ECMA 262 - 15.9.1.12
292function TimeInYear(year) {
293 return DaysInYear(year) * msPerDay;
294}
295
296
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000297var ymd_from_time_cache = [1970, 0, 1];
298var ymd_from_time_cached_time = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000299
Steve Block6ded16b2010-05-10 14:33:55 +0100300function YearFromTime(t) {
301 if (t !== ymd_from_time_cached_time) {
302 if (!$isFinite(t)) {
303 return $NaN;
Andrei Popescu31002712010-02-23 13:46:05 +0000304 }
Steve Block6ded16b2010-05-10 14:33:55 +0100305
306 %DateYMDFromTime(t, ymd_from_time_cache);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000307 ymd_from_time_cached_time = t;
Steve Block6ded16b2010-05-10 14:33:55 +0100308 }
309
310 return ymd_from_time_cache[0];
311}
312
313function MonthFromTime(t) {
314 if (t !== ymd_from_time_cached_time) {
315 if (!$isFinite(t)) {
316 return $NaN;
Andrei Popescu31002712010-02-23 13:46:05 +0000317 }
Steve Block6ded16b2010-05-10 14:33:55 +0100318 %DateYMDFromTime(t, ymd_from_time_cache);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000319 ymd_from_time_cached_time = t;
Andrei Popescu31002712010-02-23 13:46:05 +0000320 }
Steve Block6ded16b2010-05-10 14:33:55 +0100321
322 return ymd_from_time_cache[1];
Andrei Popescu31002712010-02-23 13:46:05 +0000323}
324
Steve Block6ded16b2010-05-10 14:33:55 +0100325function DateFromTime(t) {
326 if (t !== ymd_from_time_cached_time) {
327 if (!$isFinite(t)) {
328 return $NaN;
329 }
Andrei Popescu31002712010-02-23 13:46:05 +0000330
Steve Block6ded16b2010-05-10 14:33:55 +0100331 %DateYMDFromTime(t, ymd_from_time_cache);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000332 ymd_from_time_cached_time = t;
Andrei Popescu31002712010-02-23 13:46:05 +0000333 }
Steve Block6ded16b2010-05-10 14:33:55 +0100334
335 return ymd_from_time_cache[2];
Andrei Popescu31002712010-02-23 13:46:05 +0000336}
337
338
339// Compute number of days given a year, month, date.
340// Note that month and date can lie outside the normal range.
341// For example:
342// MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
343// MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
344// MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
345function MakeDay(year, month, date) {
346 if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return $NaN;
347
Steve Block8defd9f2010-07-08 12:39:36 +0100348 // Convert to integer and map -0 to 0.
349 year = TO_INTEGER_MAP_MINUS_ZERO(year);
350 month = TO_INTEGER_MAP_MINUS_ZERO(month);
351 date = TO_INTEGER_MAP_MINUS_ZERO(date);
Andrei Popescu31002712010-02-23 13:46:05 +0000352
Steve Block6ded16b2010-05-10 14:33:55 +0100353 if (year < kMinYear || year > kMaxYear ||
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000354 month < kMinMonth || month > kMaxMonth) {
Steve Block6ded16b2010-05-10 14:33:55 +0100355 return $NaN;
Andrei Popescu31002712010-02-23 13:46:05 +0000356 }
357
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000358 // Now we rely on year and month being SMIs.
359 return %DateMakeDay(year, month) + date - 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000360}
361
362
363// ECMA 262 - 15.9.1.13
364function MakeDate(day, time) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100365 var time = day * msPerDay + time;
366 // Some of our runtime funtions for computing UTC(time) rely on
367 // times not being significantly larger than MAX_TIME_MS. If there
368 // is no way that the time can be within range even after UTC
369 // conversion we return NaN immediately instead of relying on
370 // TimeClip to do it.
371 if ($abs(time) > MAX_TIME_BEFORE_UTC) return $NaN;
372 return time;
Andrei Popescu31002712010-02-23 13:46:05 +0000373}
374
375
376// ECMA 262 - 15.9.1.14
377function TimeClip(time) {
378 if (!$isFinite(time)) return $NaN;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100379 if ($abs(time) > MAX_TIME_MS) return $NaN;
Andrei Popescu31002712010-02-23 13:46:05 +0000380 return TO_INTEGER(time);
381}
382
383
384// The Date cache is used to limit the cost of parsing the same Date
385// strings over and over again.
386var Date_cache = {
387 // Cached time value.
388 time: $NaN,
389 // Cached year when interpreting the time as a local time. Only
390 // valid when the time matches cached time.
391 year: $NaN,
392 // String input for which the cached time is valid.
393 string: null
394};
395
396
397%SetCode($Date, function(year, month, date, hours, minutes, seconds, ms) {
398 if (!%_IsConstructCall()) {
399 // ECMA 262 - 15.9.2
400 return (new $Date()).toString();
401 }
402
403 // ECMA 262 - 15.9.3
404 var argc = %_ArgumentsLength();
405 var value;
406 if (argc == 0) {
407 value = %DateCurrentTime();
408
409 } else if (argc == 1) {
410 if (IS_NUMBER(year)) {
411 value = TimeClip(year);
412
413 } else if (IS_STRING(year)) {
414 // Probe the Date cache. If we already have a time value for the
415 // given time, we re-use that instead of parsing the string again.
416 var cache = Date_cache;
417 if (cache.string === year) {
418 value = cache.time;
419 } else {
420 value = DateParse(year);
421 if (!NUMBER_IS_NAN(value)) {
422 cache.time = value;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100423 cache.year = YearFromTime(LocalTimeNoCheck(value));
Andrei Popescu31002712010-02-23 13:46:05 +0000424 cache.string = year;
425 }
426 }
427
428 } else {
429 // According to ECMA 262, no hint should be given for this
430 // conversion. However, ToPrimitive defaults to STRING_HINT for
431 // Date objects which will lose precision when the Date
432 // constructor is called with another Date object as its
433 // argument. We therefore use NUMBER_HINT for the conversion,
434 // which is the default for everything else than Date objects.
435 // This makes us behave like KJS and SpiderMonkey.
436 var time = ToPrimitive(year, NUMBER_HINT);
437 value = IS_STRING(time) ? DateParse(time) : TimeClip(ToNumber(time));
438 }
439
440 } else {
441 year = ToNumber(year);
442 month = ToNumber(month);
443 date = argc > 2 ? ToNumber(date) : 1;
444 hours = argc > 3 ? ToNumber(hours) : 0;
445 minutes = argc > 4 ? ToNumber(minutes) : 0;
446 seconds = argc > 5 ? ToNumber(seconds) : 0;
447 ms = argc > 6 ? ToNumber(ms) : 0;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000448 year = (!NUMBER_IS_NAN(year) &&
449 0 <= TO_INTEGER(year) &&
450 TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
Andrei Popescu31002712010-02-23 13:46:05 +0000451 var day = MakeDay(year, month, date);
452 var time = MakeTime(hours, minutes, seconds, ms);
453 value = TimeClip(UTC(MakeDate(day, time)));
454 }
455 %_SetValueOf(this, value);
456});
457
458
Andrei Popescu31002712010-02-23 13:46:05 +0000459%FunctionSetPrototype($Date, new $Date($NaN));
460
461
462var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000463var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
464 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
Andrei Popescu31002712010-02-23 13:46:05 +0000465
466
467function TwoDigitString(value) {
468 return value < 10 ? "0" + value : "" + value;
469}
470
471
472function DateString(time) {
Andrei Popescu31002712010-02-23 13:46:05 +0000473 return WeekDays[WeekDay(time)] + ' '
Steve Block6ded16b2010-05-10 14:33:55 +0100474 + Months[MonthFromTime(time)] + ' '
475 + TwoDigitString(DateFromTime(time)) + ' '
476 + YearFromTime(time);
Andrei Popescu31002712010-02-23 13:46:05 +0000477}
478
479
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000480var LongWeekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
481 'Thursday', 'Friday', 'Saturday'];
482var LongMonths = ['January', 'February', 'March', 'April', 'May', 'June',
483 'July', 'August', 'September', 'October', 'November', 'December'];
Andrei Popescu31002712010-02-23 13:46:05 +0000484
485
486function LongDateString(time) {
Andrei Popescu31002712010-02-23 13:46:05 +0000487 return LongWeekDays[WeekDay(time)] + ', '
Steve Block6ded16b2010-05-10 14:33:55 +0100488 + LongMonths[MonthFromTime(time)] + ' '
489 + TwoDigitString(DateFromTime(time)) + ', '
490 + YearFromTime(time);
Andrei Popescu31002712010-02-23 13:46:05 +0000491}
492
493
494function TimeString(time) {
495 return TwoDigitString(HOUR_FROM_TIME(time)) + ':'
496 + TwoDigitString(MIN_FROM_TIME(time)) + ':'
497 + TwoDigitString(SEC_FROM_TIME(time));
498}
499
500
501function LocalTimezoneString(time) {
Ben Murdochd69d2e32010-03-30 12:55:27 +0100502 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
Andrei Popescu31002712010-02-23 13:46:05 +0000516 var timezoneOffset =
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100517 (DaylightSavingsOffset(time) + local_time_offset) / msPerMinute;
Andrei Popescu31002712010-02-23 13:46:05 +0000518 var sign = (timezoneOffset >= 0) ? 1 : -1;
519 var hours = FLOOR((sign * timezoneOffset)/60);
520 var min = FLOOR((sign * timezoneOffset)%60);
521 var gmt = ' GMT' + ((sign == 1) ? '+' : '-') +
522 TwoDigitString(hours) + TwoDigitString(min);
Ben Murdochd69d2e32010-03-30 12:55:27 +0100523 return gmt + ' (' + timezone + ')';
Andrei Popescu31002712010-02-23 13:46:05 +0000524}
525
526
527function DatePrintString(time) {
528 return DateString(time) + ' ' + TimeString(time);
529}
530
531// -------------------------------------------------------------------
532
533// Reused output buffer. Used when parsing date strings.
Steve Block6ded16b2010-05-10 14:33:55 +0100534var parse_buffer = $Array(8);
Andrei Popescu31002712010-02-23 13:46:05 +0000535
536// ECMA 262 - 15.9.4.2
537function DateParse(string) {
538 var arr = %DateParseString(ToString(string), parse_buffer);
539 if (IS_NULL(arr)) return $NaN;
540
541 var day = MakeDay(arr[0], arr[1], arr[2]);
Steve Block6ded16b2010-05-10 14:33:55 +0100542 var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
Andrei Popescu31002712010-02-23 13:46:05 +0000543 var date = MakeDate(day, time);
544
Steve Block6ded16b2010-05-10 14:33:55 +0100545 if (IS_NULL(arr[7])) {
Andrei Popescu31002712010-02-23 13:46:05 +0000546 return TimeClip(UTC(date));
547 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100548 return TimeClip(date - arr[7] * 1000);
Andrei Popescu31002712010-02-23 13:46:05 +0000549 }
550}
551
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;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000563 year = (!NUMBER_IS_NAN(year) &&
564 0 <= TO_INTEGER(year) &&
565 TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
Andrei Popescu31002712010-02-23 13:46:05 +0000566 var day = MakeDay(year, month, date);
567 var time = MakeTime(hours, minutes, seconds, ms);
568 return %_SetValueOf(this, TimeClip(MakeDate(day, time)));
569}
570
571
572// Mozilla-specific extension. Returns the number of milliseconds
573// elapsed since 1 January 1970 00:00:00 UTC.
574function DateNow() {
575 return %DateCurrentTime();
576}
577
578
579// ECMA 262 - 15.9.5.2
580function DateToString() {
581 var t = DATE_VALUE(this);
582 if (NUMBER_IS_NAN(t)) return kInvalidDate;
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100583 var time_zone_string = LocalTimezoneString(t); // May update local offset.
584 return DatePrintString(LocalTimeNoCheck(t)) + time_zone_string;
Andrei Popescu31002712010-02-23 13:46:05 +0000585}
586
587
588// ECMA 262 - 15.9.5.3
589function DateToDateString() {
590 var t = DATE_VALUE(this);
591 if (NUMBER_IS_NAN(t)) return kInvalidDate;
592 return DateString(LocalTimeNoCheck(t));
593}
594
595
596// ECMA 262 - 15.9.5.4
597function DateToTimeString() {
598 var t = DATE_VALUE(this);
599 if (NUMBER_IS_NAN(t)) return kInvalidDate;
Andrei Popescu6599b9d2010-04-28 13:01:47 +0100600 var time_zone_string = LocalTimezoneString(t); // May update local offset.
601 return TimeString(LocalTimeNoCheck(t)) + time_zone_string;
Andrei Popescu31002712010-02-23 13:46:05 +0000602}
603
604
605// ECMA 262 - 15.9.5.5
606function DateToLocaleString() {
Steve Block1e0659c2011-05-24 12:43:12 +0100607 return %_CallFunction(this, DateToString);
Andrei Popescu31002712010-02-23 13:46:05 +0000608}
609
610
611// ECMA 262 - 15.9.5.6
612function DateToLocaleDateString() {
613 var t = DATE_VALUE(this);
614 if (NUMBER_IS_NAN(t)) return kInvalidDate;
615 return LongDateString(LocalTimeNoCheck(t));
616}
617
618
619// ECMA 262 - 15.9.5.7
620function DateToLocaleTimeString() {
621 var t = DATE_VALUE(this);
622 if (NUMBER_IS_NAN(t)) return kInvalidDate;
623 var lt = LocalTimeNoCheck(t);
624 return TimeString(lt);
625}
626
627
628// ECMA 262 - 15.9.5.8
629function DateValueOf() {
630 return DATE_VALUE(this);
631}
632
633
634// ECMA 262 - 15.9.5.9
Andrei Popescu402d9372010-02-26 13:31:12 +0000635function DateGetTime() {
Andrei Popescu31002712010-02-23 13:46:05 +0000636 return DATE_VALUE(this);
637}
638
639
640// ECMA 262 - 15.9.5.10
641function DateGetFullYear() {
Leon Clarkeac952652010-07-15 11:15:24 +0100642 var t = DATE_VALUE(this);
643 if (NUMBER_IS_NAN(t)) return t;
644 var cache = Date_cache;
645 if (cache.time === t) return cache.year;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100646 return YearFromTime(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000647}
648
649
650// ECMA 262 - 15.9.5.11
651function DateGetUTCFullYear() {
Leon Clarkeac952652010-07-15 11:15:24 +0100652 var t = DATE_VALUE(this);
653 if (NUMBER_IS_NAN(t)) return t;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100654 return YearFromTime(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000655}
656
657
658// ECMA 262 - 15.9.5.12
659function DateGetMonth() {
Leon Clarkeac952652010-07-15 11:15:24 +0100660 var t = DATE_VALUE(this);
661 if (NUMBER_IS_NAN(t)) return t;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100662 return MonthFromTime(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000663}
664
665
666// ECMA 262 - 15.9.5.13
667function DateGetUTCMonth() {
Leon Clarkeac952652010-07-15 11:15:24 +0100668 var t = DATE_VALUE(this);
669 if (NUMBER_IS_NAN(t)) return t;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100670 return MonthFromTime(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000671}
672
673
674// ECMA 262 - 15.9.5.14
675function DateGetDate() {
Leon Clarkeac952652010-07-15 11:15:24 +0100676 var t = DATE_VALUE(this);
677 if (NUMBER_IS_NAN(t)) return t;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100678 return DateFromTime(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000679}
680
681
682// ECMA 262 - 15.9.5.15
683function DateGetUTCDate() {
Leon Clarkeac952652010-07-15 11:15:24 +0100684 var t = DATE_VALUE(this);
685 return NAN_OR_DATE_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000686}
687
688
689// ECMA 262 - 15.9.5.16
690function DateGetDay() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000691 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000692 if (NUMBER_IS_NAN(t)) return t;
693 return WeekDay(LocalTimeNoCheck(t));
694}
695
696
697// ECMA 262 - 15.9.5.17
698function DateGetUTCDay() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000699 var t = DATE_VALUE(this);
Andrei Popescu31002712010-02-23 13:46:05 +0000700 if (NUMBER_IS_NAN(t)) return t;
701 return WeekDay(t);
702}
703
704
705// ECMA 262 - 15.9.5.18
706function DateGetHours() {
Leon Clarkeac952652010-07-15 11:15:24 +0100707 var t = DATE_VALUE(this);
708 if (NUMBER_IS_NAN(t)) return t;
709 return HOUR_FROM_TIME(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000710}
711
712
713// ECMA 262 - 15.9.5.19
714function DateGetUTCHours() {
Leon Clarkeac952652010-07-15 11:15:24 +0100715 var t = DATE_VALUE(this);
716 if (NUMBER_IS_NAN(t)) return t;
717 return HOUR_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000718}
719
720
721// ECMA 262 - 15.9.5.20
722function DateGetMinutes() {
Leon Clarkeac952652010-07-15 11:15:24 +0100723 var t = DATE_VALUE(this);
724 if (NUMBER_IS_NAN(t)) return t;
725 return MIN_FROM_TIME(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000726}
727
728
729// ECMA 262 - 15.9.5.21
730function DateGetUTCMinutes() {
Leon Clarkeac952652010-07-15 11:15:24 +0100731 var t = DATE_VALUE(this);
732 return NAN_OR_MIN_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000733}
734
735
736// ECMA 262 - 15.9.5.22
737function DateGetSeconds() {
Leon Clarkeac952652010-07-15 11:15:24 +0100738 var t = DATE_VALUE(this);
739 if (NUMBER_IS_NAN(t)) return t;
740 return SEC_FROM_TIME(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000741}
742
743
744// ECMA 262 - 15.9.5.23
745function DateGetUTCSeconds() {
Leon Clarkeac952652010-07-15 11:15:24 +0100746 var t = DATE_VALUE(this);
747 return NAN_OR_SEC_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000748}
749
750
751// ECMA 262 - 15.9.5.24
752function DateGetMilliseconds() {
Leon Clarkeac952652010-07-15 11:15:24 +0100753 var t = DATE_VALUE(this);
754 if (NUMBER_IS_NAN(t)) return t;
755 return MS_FROM_TIME(LocalTimeNoCheck(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000756}
757
758
759// ECMA 262 - 15.9.5.25
760function DateGetUTCMilliseconds() {
Leon Clarkeac952652010-07-15 11:15:24 +0100761 var t = DATE_VALUE(this);
762 return NAN_OR_MS_FROM_TIME(t);
Andrei Popescu31002712010-02-23 13:46:05 +0000763}
764
765
766// ECMA 262 - 15.9.5.26
767function DateGetTimezoneOffset() {
768 var t = DATE_VALUE(this);
769 if (NUMBER_IS_NAN(t)) return t;
770 return (t - LocalTimeNoCheck(t)) / msPerMinute;
771}
772
773
774// ECMA 262 - 15.9.5.27
775function DateSetTime(ms) {
776 if (!IS_DATE(this)) ThrowDateTypeError();
777 return %_SetValueOf(this, TimeClip(ToNumber(ms)));
778}
779
780
781// ECMA 262 - 15.9.5.28
782function DateSetMilliseconds(ms) {
783 var t = LocalTime(DATE_VALUE(this));
784 ms = ToNumber(ms);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000785 var time = MakeTime(HOUR_FROM_TIME(t),
786 MIN_FROM_TIME(t),
787 SEC_FROM_TIME(t),
788 ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000789 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
790}
791
792
793// ECMA 262 - 15.9.5.29
794function DateSetUTCMilliseconds(ms) {
795 var t = DATE_VALUE(this);
796 ms = ToNumber(ms);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000797 var time = MakeTime(HOUR_FROM_TIME(t),
798 MIN_FROM_TIME(t),
799 SEC_FROM_TIME(t),
800 ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000801 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
802}
803
804
805// ECMA 262 - 15.9.5.30
806function DateSetSeconds(sec, ms) {
807 var t = LocalTime(DATE_VALUE(this));
808 sec = ToNumber(sec);
Leon Clarkeac952652010-07-15 11:15:24 +0100809 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000810 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
811 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
812}
813
814
815// ECMA 262 - 15.9.5.31
816function DateSetUTCSeconds(sec, ms) {
817 var t = DATE_VALUE(this);
818 sec = ToNumber(sec);
Leon Clarkeac952652010-07-15 11:15:24 +0100819 ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000820 var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
821 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
822}
823
824
825// ECMA 262 - 15.9.5.33
826function DateSetMinutes(min, sec, ms) {
827 var t = LocalTime(DATE_VALUE(this));
828 min = ToNumber(min);
829 var argc = %_ArgumentsLength();
Leon Clarkeac952652010-07-15 11:15:24 +0100830 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
831 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000832 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
833 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
834}
835
836
837// ECMA 262 - 15.9.5.34
838function DateSetUTCMinutes(min, sec, ms) {
839 var t = DATE_VALUE(this);
840 min = ToNumber(min);
841 var argc = %_ArgumentsLength();
Leon Clarkeac952652010-07-15 11:15:24 +0100842 sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
843 ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000844 var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
845 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
846}
847
848
849// ECMA 262 - 15.9.5.35
850function DateSetHours(hour, min, sec, ms) {
851 var t = LocalTime(DATE_VALUE(this));
852 hour = ToNumber(hour);
853 var argc = %_ArgumentsLength();
Leon Clarkeac952652010-07-15 11:15:24 +0100854 min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
855 sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
856 ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000857 var time = MakeTime(hour, min, sec, ms);
858 return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
859}
860
861
862// ECMA 262 - 15.9.5.34
863function DateSetUTCHours(hour, min, sec, ms) {
864 var t = DATE_VALUE(this);
865 hour = ToNumber(hour);
866 var argc = %_ArgumentsLength();
Leon Clarkeac952652010-07-15 11:15:24 +0100867 min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
868 sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
869 ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
Andrei Popescu31002712010-02-23 13:46:05 +0000870 var time = MakeTime(hour, min, sec, ms);
871 return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
872}
873
874
875// ECMA 262 - 15.9.5.36
876function DateSetDate(date) {
877 var t = LocalTime(DATE_VALUE(this));
878 date = ToNumber(date);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100879 var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
Andrei Popescu31002712010-02-23 13:46:05 +0000880 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
881}
882
883
884// ECMA 262 - 15.9.5.37
885function DateSetUTCDate(date) {
886 var t = DATE_VALUE(this);
887 date = ToNumber(date);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100888 var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
Andrei Popescu31002712010-02-23 13:46:05 +0000889 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
890}
891
892
893// ECMA 262 - 15.9.5.38
894function DateSetMonth(month, date) {
895 var t = LocalTime(DATE_VALUE(this));
896 month = ToNumber(month);
Leon Clarkeac952652010-07-15 11:15:24 +0100897 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100898 var day = MakeDay(YearFromTime(t), month, date);
Andrei Popescu31002712010-02-23 13:46:05 +0000899 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
900}
901
902
903// ECMA 262 - 15.9.5.39
904function DateSetUTCMonth(month, date) {
905 var t = DATE_VALUE(this);
906 month = ToNumber(month);
Leon Clarkeac952652010-07-15 11:15:24 +0100907 date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100908 var day = MakeDay(YearFromTime(t), month, date);
Andrei Popescu31002712010-02-23 13:46:05 +0000909 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
910}
911
912
913// ECMA 262 - 15.9.5.40
914function DateSetFullYear(year, month, date) {
915 var t = DATE_VALUE(this);
916 t = NUMBER_IS_NAN(t) ? 0 : LocalTimeNoCheck(t);
917 year = ToNumber(year);
918 var argc = %_ArgumentsLength();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100919 month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
920 date = argc < 3 ? DateFromTime(t) : ToNumber(date);
Andrei Popescu31002712010-02-23 13:46:05 +0000921 var day = MakeDay(year, month, date);
922 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
923}
924
925
926// ECMA 262 - 15.9.5.41
927function DateSetUTCFullYear(year, month, date) {
928 var t = DATE_VALUE(this);
929 if (NUMBER_IS_NAN(t)) t = 0;
930 var argc = %_ArgumentsLength();
931 year = ToNumber(year);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100932 month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
933 date = argc < 3 ? DateFromTime(t) : ToNumber(date);
Andrei Popescu31002712010-02-23 13:46:05 +0000934 var day = MakeDay(year, month, date);
935 return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
936}
937
938
939// ECMA 262 - 15.9.5.42
940function DateToUTCString() {
941 var t = DATE_VALUE(this);
942 if (NUMBER_IS_NAN(t)) return kInvalidDate;
943 // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
944 return WeekDays[WeekDay(t)] + ', '
Ben Murdochb0fe1622011-05-05 13:52:32 +0100945 + TwoDigitString(DateFromTime(t)) + ' '
946 + Months[MonthFromTime(t)] + ' '
947 + YearFromTime(t) + ' '
Andrei Popescu31002712010-02-23 13:46:05 +0000948 + TimeString(t) + ' GMT';
949}
950
951
952// ECMA 262 - B.2.4
953function DateGetYear() {
954 var t = DATE_VALUE(this);
955 if (NUMBER_IS_NAN(t)) return $NaN;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100956 return YearFromTime(LocalTimeNoCheck(t)) - 1900;
Andrei Popescu31002712010-02-23 13:46:05 +0000957}
958
959
960// ECMA 262 - B.2.5
961function DateSetYear(year) {
962 var t = LocalTime(DATE_VALUE(this));
963 if (NUMBER_IS_NAN(t)) t = 0;
964 year = ToNumber(year);
965 if (NUMBER_IS_NAN(year)) return %_SetValueOf(this, $NaN);
966 year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
967 ? 1900 + TO_INTEGER(year) : year;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100968 var day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
Andrei Popescu31002712010-02-23 13:46:05 +0000969 return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
970}
971
972
973// ECMA 262 - B.2.6
974//
975// Notice that this does not follow ECMA 262 completely. ECMA 262
976// says that toGMTString should be the same Function object as
977// toUTCString. JSC does not do this, so for compatibility we do not
978// do that either. Instead, we create a new function whose name
979// property will return toGMTString.
980function DateToGMTString() {
Steve Block1e0659c2011-05-24 12:43:12 +0100981 return %_CallFunction(this, DateToUTCString);
Andrei Popescu31002712010-02-23 13:46:05 +0000982}
983
984
985function PadInt(n, digits) {
986 if (digits == 1) return n;
987 return n < MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
988}
989
990
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000991// ECMA 262 - 15.9.5.43
Andrei Popescu31002712010-02-23 13:46:05 +0000992function DateToISOString() {
993 var t = DATE_VALUE(this);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000994 if (NUMBER_IS_NAN(t)) throw MakeRangeError("invalid_time_value", []);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000995 var year = this.getUTCFullYear();
996 var year_string;
997 if (year >= 0 && year <= 9999) {
998 year_string = PadInt(year, 4);
999 } else {
1000 if (year < 0) {
1001 year_string = "-" + PadInt(-year, 6);
1002 } else {
1003 year_string = "+" + PadInt(year, 6);
1004 }
1005 }
1006 return year_string +
Ben Murdochb0fe1622011-05-05 13:52:32 +01001007 '-' + PadInt(this.getUTCMonth() + 1, 2) +
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001008 '-' + PadInt(this.getUTCDate(), 2) +
Ben Murdochb0fe1622011-05-05 13:52:32 +01001009 'T' + PadInt(this.getUTCHours(), 2) +
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001010 ':' + PadInt(this.getUTCMinutes(), 2) +
Ben Murdochb0fe1622011-05-05 13:52:32 +01001011 ':' + PadInt(this.getUTCSeconds(), 2) +
Andrei Popescu31002712010-02-23 13:46:05 +00001012 '.' + PadInt(this.getUTCMilliseconds(), 3) +
1013 'Z';
1014}
1015
1016
1017function DateToJSON(key) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001018 var o = ToObject(this);
1019 var tv = DefaultNumber(o);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001020 if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) {
1021 return null;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001022 }
1023 return o.toISOString();
1024}
1025
1026
1027function ResetDateCache() {
1028
1029 // Reset the local_time_offset:
1030 local_time_offset = %DateLocalTimeOffset();
1031
1032 // Reset the DST offset cache:
1033 var cache = DST_offset_cache;
1034 cache.offset = 0;
1035 cache.start = 0;
1036 cache.end = -1;
1037 cache.increment = 0;
1038 cache.initial_increment = 19 * msPerDay;
1039
1040 // Reset the timezone cache:
1041 timezone_cache_time = $NaN;
1042 timezone_cache_timezone = undefined;
1043
1044 // Reset the ltcache:
1045 ltcache.key = null;
1046 ltcache.val = null;
1047
1048 // Reset the ymd_from_time_cache:
1049 ymd_from_time_cache = [$NaN, $NaN, $NaN];
1050 ymd_from_time_cached_time = $NaN;
1051
1052 // Reset the date cache:
1053 cache = Date_cache;
1054 cache.time = $NaN;
1055 cache.year = $NaN;
1056 cache.string = null;
Andrei Popescu31002712010-02-23 13:46:05 +00001057}
1058
1059
1060// -------------------------------------------------------------------
1061
Ben Murdoch589d6972011-11-30 16:04:58 +00001062function SetUpDate() {
1063 %CheckIsBootstrapping();
1064 // Set up non-enumerable properties of the Date object itself.
Andrei Popescu31002712010-02-23 13:46:05 +00001065 InstallFunctions($Date, DONT_ENUM, $Array(
1066 "UTC", DateUTC,
1067 "parse", DateParse,
1068 "now", DateNow
1069 ));
1070
Ben Murdoch589d6972011-11-30 16:04:58 +00001071 // Set up non-enumerable constructor property of the Date prototype object.
Andrei Popescu31002712010-02-23 13:46:05 +00001072 %SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
1073
Ben Murdoch589d6972011-11-30 16:04:58 +00001074 // Set up non-enumerable functions of the Date prototype object and
Andrei Popescu31002712010-02-23 13:46:05 +00001075 // set their names.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001076 InstallFunctions($Date.prototype, DONT_ENUM, $Array(
Andrei Popescu31002712010-02-23 13:46:05 +00001077 "toString", DateToString,
1078 "toDateString", DateToDateString,
1079 "toTimeString", DateToTimeString,
1080 "toLocaleString", DateToLocaleString,
1081 "toLocaleDateString", DateToLocaleDateString,
1082 "toLocaleTimeString", DateToLocaleTimeString,
1083 "valueOf", DateValueOf,
1084 "getTime", DateGetTime,
1085 "getFullYear", DateGetFullYear,
1086 "getUTCFullYear", DateGetUTCFullYear,
1087 "getMonth", DateGetMonth,
1088 "getUTCMonth", DateGetUTCMonth,
1089 "getDate", DateGetDate,
1090 "getUTCDate", DateGetUTCDate,
1091 "getDay", DateGetDay,
1092 "getUTCDay", DateGetUTCDay,
1093 "getHours", DateGetHours,
1094 "getUTCHours", DateGetUTCHours,
1095 "getMinutes", DateGetMinutes,
1096 "getUTCMinutes", DateGetUTCMinutes,
1097 "getSeconds", DateGetSeconds,
1098 "getUTCSeconds", DateGetUTCSeconds,
1099 "getMilliseconds", DateGetMilliseconds,
1100 "getUTCMilliseconds", DateGetUTCMilliseconds,
1101 "getTimezoneOffset", DateGetTimezoneOffset,
1102 "setTime", DateSetTime,
1103 "setMilliseconds", DateSetMilliseconds,
1104 "setUTCMilliseconds", DateSetUTCMilliseconds,
1105 "setSeconds", DateSetSeconds,
1106 "setUTCSeconds", DateSetUTCSeconds,
1107 "setMinutes", DateSetMinutes,
1108 "setUTCMinutes", DateSetUTCMinutes,
1109 "setHours", DateSetHours,
1110 "setUTCHours", DateSetUTCHours,
1111 "setDate", DateSetDate,
1112 "setUTCDate", DateSetUTCDate,
1113 "setMonth", DateSetMonth,
1114 "setUTCMonth", DateSetUTCMonth,
1115 "setFullYear", DateSetFullYear,
1116 "setUTCFullYear", DateSetUTCFullYear,
1117 "toGMTString", DateToGMTString,
1118 "toUTCString", DateToUTCString,
1119 "getYear", DateGetYear,
1120 "setYear", DateSetYear,
1121 "toISOString", DateToISOString,
1122 "toJSON", DateToJSON
1123 ));
1124}
1125
Ben Murdoch589d6972011-11-30 16:04:58 +00001126SetUpDate();