1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsdate.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3182 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JS date methods. 1.12 + * 1.13 + * "For example, OS/360 devotes 26 bytes of the permanently 1.14 + * resident date-turnover routine to the proper handling of 1.15 + * December 31 on leap years (when it is Day 366). That 1.16 + * might have been left to the operator." 1.17 + * 1.18 + * Frederick Brooks, 'The Second-System Effect'. 1.19 + */ 1.20 + 1.21 +#include "jsdate.h" 1.22 + 1.23 +#include "mozilla/ArrayUtils.h" 1.24 +#include "mozilla/FloatingPoint.h" 1.25 + 1.26 +#include <ctype.h> 1.27 +#include <math.h> 1.28 +#include <string.h> 1.29 + 1.30 +#include "jsapi.h" 1.31 +#include "jscntxt.h" 1.32 +#include "jsnum.h" 1.33 +#include "jsobj.h" 1.34 +#include "jsprf.h" 1.35 +#include "jsstr.h" 1.36 +#include "jstypes.h" 1.37 +#include "jsutil.h" 1.38 +#include "prmjtime.h" 1.39 + 1.40 +#include "js/Date.h" 1.41 +#include "vm/DateTime.h" 1.42 +#include "vm/GlobalObject.h" 1.43 +#include "vm/Interpreter.h" 1.44 +#include "vm/NumericConversions.h" 1.45 +#include "vm/String.h" 1.46 +#include "vm/StringBuffer.h" 1.47 + 1.48 +#include "jsobjinlines.h" 1.49 + 1.50 +using namespace js; 1.51 +using namespace js::types; 1.52 + 1.53 +using mozilla::ArrayLength; 1.54 +using mozilla::IsFinite; 1.55 +using mozilla::IsNaN; 1.56 +using JS::GenericNaN; 1.57 + 1.58 +/* 1.59 + * The JS 'Date' object is patterned after the Java 'Date' object. 1.60 + * Here is a script: 1.61 + * 1.62 + * today = new Date(); 1.63 + * 1.64 + * print(today.toLocaleString()); 1.65 + * 1.66 + * weekDay = today.getDay(); 1.67 + * 1.68 + * 1.69 + * These Java (and ECMA-262) methods are supported: 1.70 + * 1.71 + * UTC 1.72 + * getDate (getUTCDate) 1.73 + * getDay (getUTCDay) 1.74 + * getHours (getUTCHours) 1.75 + * getMinutes (getUTCMinutes) 1.76 + * getMonth (getUTCMonth) 1.77 + * getSeconds (getUTCSeconds) 1.78 + * getMilliseconds (getUTCMilliseconds) 1.79 + * getTime 1.80 + * getTimezoneOffset 1.81 + * getYear 1.82 + * getFullYear (getUTCFullYear) 1.83 + * parse 1.84 + * setDate (setUTCDate) 1.85 + * setHours (setUTCHours) 1.86 + * setMinutes (setUTCMinutes) 1.87 + * setMonth (setUTCMonth) 1.88 + * setSeconds (setUTCSeconds) 1.89 + * setMilliseconds (setUTCMilliseconds) 1.90 + * setTime 1.91 + * setYear (setFullYear, setUTCFullYear) 1.92 + * toGMTString (toUTCString) 1.93 + * toLocaleString 1.94 + * toString 1.95 + * 1.96 + * 1.97 + * These Java methods are not supported 1.98 + * 1.99 + * setDay 1.100 + * before 1.101 + * after 1.102 + * equals 1.103 + * hashCode 1.104 + */ 1.105 + 1.106 +static inline double 1.107 +Day(double t) 1.108 +{ 1.109 + return floor(t / msPerDay); 1.110 +} 1.111 + 1.112 +static double 1.113 +TimeWithinDay(double t) 1.114 +{ 1.115 + double result = fmod(t, msPerDay); 1.116 + if (result < 0) 1.117 + result += msPerDay; 1.118 + return result; 1.119 +} 1.120 + 1.121 +/* ES5 15.9.1.3. */ 1.122 +static inline bool 1.123 +IsLeapYear(double year) 1.124 +{ 1.125 + JS_ASSERT(ToInteger(year) == year); 1.126 + return fmod(year, 4) == 0 && (fmod(year, 100) != 0 || fmod(year, 400) == 0); 1.127 +} 1.128 + 1.129 +static inline double 1.130 +DaysInYear(double year) 1.131 +{ 1.132 + if (!IsFinite(year)) 1.133 + return GenericNaN(); 1.134 + return IsLeapYear(year) ? 366 : 365; 1.135 +} 1.136 + 1.137 +static inline double 1.138 +DayFromYear(double y) 1.139 +{ 1.140 + return 365 * (y - 1970) + 1.141 + floor((y - 1969) / 4.0) - 1.142 + floor((y - 1901) / 100.0) + 1.143 + floor((y - 1601) / 400.0); 1.144 +} 1.145 + 1.146 +static inline double 1.147 +TimeFromYear(double y) 1.148 +{ 1.149 + return DayFromYear(y) * msPerDay; 1.150 +} 1.151 + 1.152 +static double 1.153 +YearFromTime(double t) 1.154 +{ 1.155 + if (!IsFinite(t)) 1.156 + return GenericNaN(); 1.157 + 1.158 + JS_ASSERT(ToInteger(t) == t); 1.159 + 1.160 + double y = floor(t / (msPerDay * 365.2425)) + 1970; 1.161 + double t2 = TimeFromYear(y); 1.162 + 1.163 + /* 1.164 + * Adjust the year if the approximation was wrong. Since the year was 1.165 + * computed using the average number of ms per year, it will usually 1.166 + * be wrong for dates within several hours of a year transition. 1.167 + */ 1.168 + if (t2 > t) { 1.169 + y--; 1.170 + } else { 1.171 + if (t2 + msPerDay * DaysInYear(y) <= t) 1.172 + y++; 1.173 + } 1.174 + return y; 1.175 +} 1.176 + 1.177 +static inline int 1.178 +DaysInFebruary(double year) 1.179 +{ 1.180 + return IsLeapYear(year) ? 29 : 28; 1.181 +} 1.182 + 1.183 +/* ES5 15.9.1.4. */ 1.184 +static inline double 1.185 +DayWithinYear(double t, double year) 1.186 +{ 1.187 + JS_ASSERT_IF(IsFinite(t), YearFromTime(t) == year); 1.188 + return Day(t) - DayFromYear(year); 1.189 +} 1.190 + 1.191 +static double 1.192 +MonthFromTime(double t) 1.193 +{ 1.194 + if (!IsFinite(t)) 1.195 + return GenericNaN(); 1.196 + 1.197 + double year = YearFromTime(t); 1.198 + double d = DayWithinYear(t, year); 1.199 + 1.200 + int step; 1.201 + if (d < (step = 31)) 1.202 + return 0; 1.203 + if (d < (step += DaysInFebruary(year))) 1.204 + return 1; 1.205 + if (d < (step += 31)) 1.206 + return 2; 1.207 + if (d < (step += 30)) 1.208 + return 3; 1.209 + if (d < (step += 31)) 1.210 + return 4; 1.211 + if (d < (step += 30)) 1.212 + return 5; 1.213 + if (d < (step += 31)) 1.214 + return 6; 1.215 + if (d < (step += 31)) 1.216 + return 7; 1.217 + if (d < (step += 30)) 1.218 + return 8; 1.219 + if (d < (step += 31)) 1.220 + return 9; 1.221 + if (d < (step += 30)) 1.222 + return 10; 1.223 + return 11; 1.224 +} 1.225 + 1.226 +/* ES5 15.9.1.5. */ 1.227 +static double 1.228 +DateFromTime(double t) 1.229 +{ 1.230 + if (!IsFinite(t)) 1.231 + return GenericNaN(); 1.232 + 1.233 + double year = YearFromTime(t); 1.234 + double d = DayWithinYear(t, year); 1.235 + 1.236 + int next; 1.237 + if (d <= (next = 30)) 1.238 + return d + 1; 1.239 + int step = next; 1.240 + if (d <= (next += DaysInFebruary(year))) 1.241 + return d - step; 1.242 + step = next; 1.243 + if (d <= (next += 31)) 1.244 + return d - step; 1.245 + step = next; 1.246 + if (d <= (next += 30)) 1.247 + return d - step; 1.248 + step = next; 1.249 + if (d <= (next += 31)) 1.250 + return d - step; 1.251 + step = next; 1.252 + if (d <= (next += 30)) 1.253 + return d - step; 1.254 + step = next; 1.255 + if (d <= (next += 31)) 1.256 + return d - step; 1.257 + step = next; 1.258 + if (d <= (next += 31)) 1.259 + return d - step; 1.260 + step = next; 1.261 + if (d <= (next += 30)) 1.262 + return d - step; 1.263 + step = next; 1.264 + if (d <= (next += 31)) 1.265 + return d - step; 1.266 + step = next; 1.267 + if (d <= (next += 30)) 1.268 + return d - step; 1.269 + step = next; 1.270 + return d - step; 1.271 +} 1.272 + 1.273 +/* ES5 15.9.1.6. */ 1.274 +static int 1.275 +WeekDay(double t) 1.276 +{ 1.277 + /* 1.278 + * We can't assert TimeClip(t) == t because we call this function with 1.279 + * local times, which can be offset outside TimeClip's permitted range. 1.280 + */ 1.281 + JS_ASSERT(ToInteger(t) == t); 1.282 + int result = (int(Day(t)) + 4) % 7; 1.283 + if (result < 0) 1.284 + result += 7; 1.285 + return result; 1.286 +} 1.287 + 1.288 +static inline int 1.289 +DayFromMonth(int month, bool isLeapYear) 1.290 +{ 1.291 + /* 1.292 + * The following array contains the day of year for the first day of 1.293 + * each month, where index 0 is January, and day 0 is January 1. 1.294 + */ 1.295 + static const int firstDayOfMonth[2][13] = { 1.296 + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, 1.297 + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} 1.298 + }; 1.299 + 1.300 + JS_ASSERT(0 <= month && month <= 12); 1.301 + return firstDayOfMonth[isLeapYear][month]; 1.302 +} 1.303 + 1.304 +template<typename T> 1.305 +static inline int 1.306 +DayFromMonth(T month, bool isLeapYear) MOZ_DELETE; 1.307 + 1.308 +/* ES5 15.9.1.12 (out of order to accommodate DaylightSavingTA). */ 1.309 +static double 1.310 +MakeDay(double year, double month, double date) 1.311 +{ 1.312 + /* Step 1. */ 1.313 + if (!IsFinite(year) || !IsFinite(month) || !IsFinite(date)) 1.314 + return GenericNaN(); 1.315 + 1.316 + /* Steps 2-4. */ 1.317 + double y = ToInteger(year); 1.318 + double m = ToInteger(month); 1.319 + double dt = ToInteger(date); 1.320 + 1.321 + /* Step 5. */ 1.322 + double ym = y + floor(m / 12); 1.323 + 1.324 + /* Step 6. */ 1.325 + int mn = int(fmod(m, 12.0)); 1.326 + if (mn < 0) 1.327 + mn += 12; 1.328 + 1.329 + /* Steps 7-8. */ 1.330 + bool leap = IsLeapYear(ym); 1.331 + 1.332 + double yearday = floor(TimeFromYear(ym) / msPerDay); 1.333 + double monthday = DayFromMonth(mn, leap); 1.334 + 1.335 + return yearday + monthday + dt - 1; 1.336 +} 1.337 + 1.338 +/* ES5 15.9.1.13 (out of order to accommodate DaylightSavingTA). */ 1.339 +static inline double 1.340 +MakeDate(double day, double time) 1.341 +{ 1.342 + /* Step 1. */ 1.343 + if (!IsFinite(day) || !IsFinite(time)) 1.344 + return GenericNaN(); 1.345 + 1.346 + /* Step 2. */ 1.347 + return day * msPerDay + time; 1.348 +} 1.349 + 1.350 +JS_PUBLIC_API(double) 1.351 +JS::MakeDate(double year, unsigned month, unsigned day) 1.352 +{ 1.353 + return TimeClip(::MakeDate(MakeDay(year, month, day), 0)); 1.354 +} 1.355 + 1.356 +JS_PUBLIC_API(double) 1.357 +JS::YearFromTime(double time) 1.358 +{ 1.359 + return ::YearFromTime(time); 1.360 +} 1.361 + 1.362 +JS_PUBLIC_API(double) 1.363 +JS::MonthFromTime(double time) 1.364 +{ 1.365 + return ::MonthFromTime(time); 1.366 +} 1.367 + 1.368 +JS_PUBLIC_API(double) 1.369 +JS::DayFromTime(double time) 1.370 +{ 1.371 + return DateFromTime(time); 1.372 +} 1.373 + 1.374 +/* 1.375 + * Find a year for which any given date will fall on the same weekday. 1.376 + * 1.377 + * This function should be used with caution when used other than 1.378 + * for determining DST; it hasn't been proven not to produce an 1.379 + * incorrect year for times near year boundaries. 1.380 + */ 1.381 +static int 1.382 +EquivalentYearForDST(int year) 1.383 +{ 1.384 + /* 1.385 + * Years and leap years on which Jan 1 is a Sunday, Monday, etc. 1.386 + * 1.387 + * yearStartingWith[0][i] is an example non-leap year where 1.388 + * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. 1.389 + * 1.390 + * yearStartingWith[1][i] is an example leap year where 1.391 + * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. 1.392 + */ 1.393 + static const int yearStartingWith[2][7] = { 1.394 + {1978, 1973, 1974, 1975, 1981, 1971, 1977}, 1.395 + {1984, 1996, 1980, 1992, 1976, 1988, 1972} 1.396 + }; 1.397 + 1.398 + int day = int(DayFromYear(year) + 4) % 7; 1.399 + if (day < 0) 1.400 + day += 7; 1.401 + 1.402 + return yearStartingWith[IsLeapYear(year)][day]; 1.403 +} 1.404 + 1.405 +/* ES5 15.9.1.8. */ 1.406 +static double 1.407 +DaylightSavingTA(double t, DateTimeInfo *dtInfo) 1.408 +{ 1.409 + if (!IsFinite(t)) 1.410 + return GenericNaN(); 1.411 + 1.412 + /* 1.413 + * If earlier than 1970 or after 2038, potentially beyond the ken of 1.414 + * many OSes, map it to an equivalent year before asking. 1.415 + */ 1.416 + if (t < 0.0 || t > 2145916800000.0) { 1.417 + int year = EquivalentYearForDST(int(YearFromTime(t))); 1.418 + double day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); 1.419 + t = MakeDate(day, TimeWithinDay(t)); 1.420 + } 1.421 + 1.422 + int64_t utcMilliseconds = static_cast<int64_t>(t); 1.423 + int64_t offsetMilliseconds = dtInfo->getDSTOffsetMilliseconds(utcMilliseconds); 1.424 + return static_cast<double>(offsetMilliseconds); 1.425 +} 1.426 + 1.427 +static double 1.428 +AdjustTime(double date, DateTimeInfo *dtInfo) 1.429 +{ 1.430 + double t = DaylightSavingTA(date, dtInfo) + dtInfo->localTZA(); 1.431 + t = (dtInfo->localTZA() >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay); 1.432 + return t; 1.433 +} 1.434 + 1.435 +/* ES5 15.9.1.9. */ 1.436 +static double 1.437 +LocalTime(double t, DateTimeInfo *dtInfo) 1.438 +{ 1.439 + return t + AdjustTime(t, dtInfo); 1.440 +} 1.441 + 1.442 +static double 1.443 +UTC(double t, DateTimeInfo *dtInfo) 1.444 +{ 1.445 + return t - AdjustTime(t - dtInfo->localTZA(), dtInfo); 1.446 +} 1.447 + 1.448 +/* ES5 15.9.1.10. */ 1.449 +static double 1.450 +HourFromTime(double t) 1.451 +{ 1.452 + double result = fmod(floor(t/msPerHour), HoursPerDay); 1.453 + if (result < 0) 1.454 + result += HoursPerDay; 1.455 + return result; 1.456 +} 1.457 + 1.458 +static double 1.459 +MinFromTime(double t) 1.460 +{ 1.461 + double result = fmod(floor(t / msPerMinute), MinutesPerHour); 1.462 + if (result < 0) 1.463 + result += MinutesPerHour; 1.464 + return result; 1.465 +} 1.466 + 1.467 +static double 1.468 +SecFromTime(double t) 1.469 +{ 1.470 + double result = fmod(floor(t / msPerSecond), SecondsPerMinute); 1.471 + if (result < 0) 1.472 + result += SecondsPerMinute; 1.473 + return result; 1.474 +} 1.475 + 1.476 +static double 1.477 +msFromTime(double t) 1.478 +{ 1.479 + double result = fmod(t, msPerSecond); 1.480 + if (result < 0) 1.481 + result += msPerSecond; 1.482 + return result; 1.483 +} 1.484 + 1.485 +/* ES5 15.9.1.11. */ 1.486 +static double 1.487 +MakeTime(double hour, double min, double sec, double ms) 1.488 +{ 1.489 + /* Step 1. */ 1.490 + if (!IsFinite(hour) || 1.491 + !IsFinite(min) || 1.492 + !IsFinite(sec) || 1.493 + !IsFinite(ms)) 1.494 + { 1.495 + return GenericNaN(); 1.496 + } 1.497 + 1.498 + /* Step 2. */ 1.499 + double h = ToInteger(hour); 1.500 + 1.501 + /* Step 3. */ 1.502 + double m = ToInteger(min); 1.503 + 1.504 + /* Step 4. */ 1.505 + double s = ToInteger(sec); 1.506 + 1.507 + /* Step 5. */ 1.508 + double milli = ToInteger(ms); 1.509 + 1.510 + /* Steps 6-7. */ 1.511 + return h * msPerHour + m * msPerMinute + s * msPerSecond + milli; 1.512 +} 1.513 + 1.514 +/** 1.515 + * end of ECMA 'support' functions 1.516 + */ 1.517 + 1.518 +static bool 1.519 +date_convert(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) 1.520 +{ 1.521 + JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID); 1.522 + JS_ASSERT(obj->is<DateObject>()); 1.523 + 1.524 + return DefaultValue(cx, obj, (hint == JSTYPE_VOID) ? JSTYPE_STRING : hint, vp); 1.525 +} 1.526 + 1.527 +/* for use by date_parse */ 1.528 + 1.529 +static const char* const wtb[] = { 1.530 + "am", "pm", 1.531 + "monday", "tuesday", "wednesday", "thursday", "friday", 1.532 + "saturday", "sunday", 1.533 + "january", "february", "march", "april", "may", "june", 1.534 + "july", "august", "september", "october", "november", "december", 1.535 + "gmt", "ut", "utc", 1.536 + "est", "edt", 1.537 + "cst", "cdt", 1.538 + "mst", "mdt", 1.539 + "pst", "pdt" 1.540 + /* time zone table needs to be expanded */ 1.541 +}; 1.542 + 1.543 +static const int ttb[] = { 1.544 + -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */ 1.545 + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.546 + 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */ 1.547 + 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */ 1.548 + 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */ 1.549 + 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */ 1.550 + 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */ 1.551 +}; 1.552 + 1.553 +/* helper for date_parse */ 1.554 +static bool 1.555 +date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off, 1.556 + int count, int ignoreCase) 1.557 +{ 1.558 + bool result = false; 1.559 + /* return true if matches, otherwise, false */ 1.560 + 1.561 + while (count > 0 && s1[s1off] && s2[s2off]) { 1.562 + if (ignoreCase) { 1.563 + if (unicode::ToLowerCase(s1[s1off]) != unicode::ToLowerCase(s2[s2off])) 1.564 + break; 1.565 + } else { 1.566 + if ((jschar)s1[s1off] != s2[s2off]) { 1.567 + break; 1.568 + } 1.569 + } 1.570 + s1off++; 1.571 + s2off++; 1.572 + count--; 1.573 + } 1.574 + 1.575 + if (count == 0) { 1.576 + result = true; 1.577 + } 1.578 + 1.579 + return result; 1.580 +} 1.581 + 1.582 +/* find UTC time from given date... no 1900 correction! */ 1.583 +static double 1.584 +date_msecFromDate(double year, double mon, double mday, double hour, 1.585 + double min, double sec, double msec) 1.586 +{ 1.587 + return MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, msec)); 1.588 +} 1.589 + 1.590 +/* compute the time in msec (unclipped) from the given args */ 1.591 +#define MAXARGS 7 1.592 + 1.593 +static bool 1.594 +date_msecFromArgs(JSContext *cx, CallArgs args, double *rval) 1.595 +{ 1.596 + unsigned loop; 1.597 + double array[MAXARGS]; 1.598 + double msec_time; 1.599 + 1.600 + for (loop = 0; loop < MAXARGS; loop++) { 1.601 + if (loop < args.length()) { 1.602 + double d; 1.603 + if (!ToNumber(cx, args[loop], &d)) 1.604 + return false; 1.605 + /* return NaN if any arg is not finite */ 1.606 + if (!IsFinite(d)) { 1.607 + *rval = GenericNaN(); 1.608 + return true; 1.609 + } 1.610 + array[loop] = ToInteger(d); 1.611 + } else { 1.612 + if (loop == 2) { 1.613 + array[loop] = 1; /* Default the date argument to 1. */ 1.614 + } else { 1.615 + array[loop] = 0; 1.616 + } 1.617 + } 1.618 + } 1.619 + 1.620 + /* adjust 2-digit years into the 20th century */ 1.621 + if (array[0] >= 0 && array[0] <= 99) 1.622 + array[0] += 1900; 1.623 + 1.624 + msec_time = date_msecFromDate(array[0], array[1], array[2], 1.625 + array[3], array[4], array[5], array[6]); 1.626 + *rval = msec_time; 1.627 + return true; 1.628 +} 1.629 + 1.630 +/* 1.631 + * See ECMA 15.9.4.[3-10]; 1.632 + */ 1.633 +static bool 1.634 +date_UTC(JSContext *cx, unsigned argc, Value *vp) 1.635 +{ 1.636 + CallArgs args = CallArgsFromVp(argc, vp); 1.637 + 1.638 + double msec_time; 1.639 + if (!date_msecFromArgs(cx, args, &msec_time)) 1.640 + return false; 1.641 + 1.642 + msec_time = TimeClip(msec_time); 1.643 + 1.644 + args.rval().setNumber(msec_time); 1.645 + return true; 1.646 +} 1.647 + 1.648 +/* 1.649 + * Read and convert decimal digits from s[*i] into *result 1.650 + * while *i < limit. 1.651 + * 1.652 + * Succeed if any digits are converted. Advance *i only 1.653 + * as digits are consumed. 1.654 + */ 1.655 +static bool 1.656 +digits(size_t *result, const jschar *s, size_t *i, size_t limit) 1.657 +{ 1.658 + size_t init = *i; 1.659 + *result = 0; 1.660 + while (*i < limit && 1.661 + ('0' <= s[*i] && s[*i] <= '9')) { 1.662 + *result *= 10; 1.663 + *result += (s[*i] - '0'); 1.664 + ++(*i); 1.665 + } 1.666 + return *i != init; 1.667 +} 1.668 + 1.669 +/* 1.670 + * Read and convert decimal digits to the right of a decimal point, 1.671 + * representing a fractional integer, from s[*i] into *result 1.672 + * while *i < limit. 1.673 + * 1.674 + * Succeed if any digits are converted. Advance *i only 1.675 + * as digits are consumed. 1.676 + */ 1.677 +static bool 1.678 +fractional(double *result, const jschar *s, size_t *i, size_t limit) 1.679 +{ 1.680 + double factor = 0.1; 1.681 + size_t init = *i; 1.682 + *result = 0.0; 1.683 + while (*i < limit && 1.684 + ('0' <= s[*i] && s[*i] <= '9')) { 1.685 + *result += (s[*i] - '0') * factor; 1.686 + factor *= 0.1; 1.687 + ++(*i); 1.688 + } 1.689 + return *i != init; 1.690 +} 1.691 + 1.692 +/* 1.693 + * Read and convert exactly n decimal digits from s[*i] 1.694 + * to s[min(*i+n,limit)] into *result. 1.695 + * 1.696 + * Succeed if exactly n digits are converted. Advance *i only 1.697 + * on success. 1.698 + */ 1.699 +static bool 1.700 +ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit) 1.701 +{ 1.702 + size_t init = *i; 1.703 + 1.704 + if (digits(result, s, i, Min(limit, init+n))) 1.705 + return (*i - init) == n; 1.706 + 1.707 + *i = init; 1.708 + return false; 1.709 +} 1.710 + 1.711 +static int 1.712 +DaysInMonth(int year, int month) 1.713 +{ 1.714 + bool leap = IsLeapYear(year); 1.715 + int result = int(DayFromMonth(month, leap) - DayFromMonth(month - 1, leap)); 1.716 + return result; 1.717 +} 1.718 + 1.719 +/* 1.720 + * Parse a string in one of the date-time formats given by the W3C 1.721 + * "NOTE-datetime" specification. These formats make up a restricted 1.722 + * profile of the ISO 8601 format. Quoted here: 1.723 + * 1.724 + * The formats are as follows. Exactly the components shown here 1.725 + * must be present, with exactly this punctuation. Note that the "T" 1.726 + * appears literally in the string, to indicate the beginning of the 1.727 + * time element, as specified in ISO 8601. 1.728 + * 1.729 + * Any combination of the date formats with the time formats is 1.730 + * allowed, and also either the date or the time can be missing. 1.731 + * 1.732 + * The specification is silent on the meaning when fields are 1.733 + * ommitted so the interpretations are a guess, but hopefully a 1.734 + * reasonable one. We default the month to January, the day to the 1.735 + * 1st, and hours minutes and seconds all to 0. If the date is 1.736 + * missing entirely then we assume 1970-01-01 so that the time can 1.737 + * be aded to a date later. If the time is missing then we assume 1.738 + * 00:00 UTC. If the time is present but the time zone field is 1.739 + * missing then we use local time. 1.740 + * 1.741 + * Date part: 1.742 + * 1.743 + * Year: 1.744 + * YYYY (eg 1997) 1.745 + * 1.746 + * Year and month: 1.747 + * YYYY-MM (eg 1997-07) 1.748 + * 1.749 + * Complete date: 1.750 + * YYYY-MM-DD (eg 1997-07-16) 1.751 + * 1.752 + * Time part: 1.753 + * 1.754 + * Hours and minutes: 1.755 + * Thh:mmTZD (eg T19:20+01:00) 1.756 + * 1.757 + * Hours, minutes and seconds: 1.758 + * Thh:mm:ssTZD (eg T19:20:30+01:00) 1.759 + * 1.760 + * Hours, minutes, seconds and a decimal fraction of a second: 1.761 + * Thh:mm:ss.sTZD (eg T19:20:30.45+01:00) 1.762 + * 1.763 + * where: 1.764 + * 1.765 + * YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY 1.766 + * MM = two-digit month (01=January, etc.) 1.767 + * DD = two-digit day of month (01 through 31) 1.768 + * hh = two digits of hour (00 through 23) (am/pm NOT allowed) 1.769 + * mm = two digits of minute (00 through 59) 1.770 + * ss = two digits of second (00 through 59) 1.771 + * s = one or more digits representing a decimal fraction of a second 1.772 + * TZD = time zone designator (Z or +hh:mm or -hh:mm or missing for local) 1.773 + */ 1.774 + 1.775 +static bool 1.776 +date_parseISOString(JSLinearString *str, double *result, DateTimeInfo *dtInfo) 1.777 +{ 1.778 + double msec; 1.779 + 1.780 + const jschar *s; 1.781 + size_t limit; 1.782 + size_t i = 0; 1.783 + int tzMul = 1; 1.784 + int dateMul = 1; 1.785 + size_t year = 1970; 1.786 + size_t month = 1; 1.787 + size_t day = 1; 1.788 + size_t hour = 0; 1.789 + size_t min = 0; 1.790 + size_t sec = 0; 1.791 + double frac = 0; 1.792 + bool isLocalTime = false; 1.793 + size_t tzHour = 0; 1.794 + size_t tzMin = 0; 1.795 + 1.796 +#define PEEK(ch) (i < limit && s[i] == ch) 1.797 + 1.798 +#define NEED(ch) \ 1.799 + JS_BEGIN_MACRO \ 1.800 + if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \ 1.801 + JS_END_MACRO 1.802 + 1.803 +#define DONE_DATE_UNLESS(ch) \ 1.804 + JS_BEGIN_MACRO \ 1.805 + if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \ 1.806 + JS_END_MACRO 1.807 + 1.808 +#define DONE_UNLESS(ch) \ 1.809 + JS_BEGIN_MACRO \ 1.810 + if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \ 1.811 + JS_END_MACRO 1.812 + 1.813 +#define NEED_NDIGITS(n, field) \ 1.814 + JS_BEGIN_MACRO \ 1.815 + if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \ 1.816 + JS_END_MACRO 1.817 + 1.818 + s = str->chars(); 1.819 + limit = str->length(); 1.820 + 1.821 + if (PEEK('+') || PEEK('-')) { 1.822 + if (PEEK('-')) 1.823 + dateMul = -1; 1.824 + ++i; 1.825 + NEED_NDIGITS(6, year); 1.826 + } else if (!PEEK('T')) { 1.827 + NEED_NDIGITS(4, year); 1.828 + } 1.829 + DONE_DATE_UNLESS('-'); 1.830 + NEED_NDIGITS(2, month); 1.831 + DONE_DATE_UNLESS('-'); 1.832 + NEED_NDIGITS(2, day); 1.833 + 1.834 + done_date: 1.835 + DONE_UNLESS('T'); 1.836 + NEED_NDIGITS(2, hour); 1.837 + NEED(':'); 1.838 + NEED_NDIGITS(2, min); 1.839 + 1.840 + if (PEEK(':')) { 1.841 + ++i; 1.842 + NEED_NDIGITS(2, sec); 1.843 + if (PEEK('.')) { 1.844 + ++i; 1.845 + if (!fractional(&frac, s, &i, limit)) 1.846 + goto syntax; 1.847 + } 1.848 + } 1.849 + 1.850 + if (PEEK('Z')) { 1.851 + ++i; 1.852 + } else if (PEEK('+') || PEEK('-')) { 1.853 + if (PEEK('-')) 1.854 + tzMul = -1; 1.855 + ++i; 1.856 + NEED_NDIGITS(2, tzHour); 1.857 + /* 1.858 + * Non-standard extension to the ISO date format (permitted by ES5): 1.859 + * allow "-0700" as a time zone offset, not just "-07:00". 1.860 + */ 1.861 + if (PEEK(':')) 1.862 + ++i; 1.863 + NEED_NDIGITS(2, tzMin); 1.864 + } else { 1.865 + isLocalTime = true; 1.866 + } 1.867 + 1.868 + done: 1.869 + if (year > 275943 // ceil(1e8/365) + 1970 1.870 + || (month == 0 || month > 12) 1.871 + || (day == 0 || day > size_t(DaysInMonth(year,month))) 1.872 + || hour > 24 1.873 + || ((hour == 24) && (min > 0 || sec > 0)) 1.874 + || min > 59 1.875 + || sec > 59 1.876 + || tzHour > 23 1.877 + || tzMin > 59) 1.878 + goto syntax; 1.879 + 1.880 + if (i != limit) 1.881 + goto syntax; 1.882 + 1.883 + month -= 1; /* convert month to 0-based */ 1.884 + 1.885 + msec = date_msecFromDate(dateMul * (double)year, month, day, 1.886 + hour, min, sec, 1.887 + frac * 1000.0);; 1.888 + 1.889 + if (isLocalTime) { 1.890 + msec = UTC(msec, dtInfo); 1.891 + } else { 1.892 + msec -= ((tzMul) * ((tzHour * msPerHour) 1.893 + + (tzMin * msPerMinute))); 1.894 + } 1.895 + 1.896 + if (msec < -8.64e15 || msec > 8.64e15) 1.897 + goto syntax; 1.898 + 1.899 + *result = msec; 1.900 + 1.901 + return true; 1.902 + 1.903 + syntax: 1.904 + /* syntax error */ 1.905 + *result = 0; 1.906 + return false; 1.907 + 1.908 +#undef PEEK 1.909 +#undef NEED 1.910 +#undef DONE_UNLESS 1.911 +#undef NEED_NDIGITS 1.912 +} 1.913 + 1.914 +static bool 1.915 +date_parseString(JSLinearString *str, double *result, DateTimeInfo *dtInfo) 1.916 +{ 1.917 + double msec; 1.918 + 1.919 + const jschar *s; 1.920 + size_t limit; 1.921 + size_t i = 0; 1.922 + int year = -1; 1.923 + int mon = -1; 1.924 + int mday = -1; 1.925 + int hour = -1; 1.926 + int min = -1; 1.927 + int sec = -1; 1.928 + int c = -1; 1.929 + int n = -1; 1.930 + int tzoffset = -1; 1.931 + int prevc = 0; 1.932 + bool seenplusminus = false; 1.933 + int temp; 1.934 + bool seenmonthname = false; 1.935 + 1.936 + if (date_parseISOString(str, result, dtInfo)) 1.937 + return true; 1.938 + 1.939 + s = str->chars(); 1.940 + limit = str->length(); 1.941 + if (limit == 0) 1.942 + goto syntax; 1.943 + while (i < limit) { 1.944 + c = s[i]; 1.945 + i++; 1.946 + if (c <= ' ' || c == ',' || c == '-') { 1.947 + if (c == '-' && '0' <= s[i] && s[i] <= '9') { 1.948 + prevc = c; 1.949 + } 1.950 + continue; 1.951 + } 1.952 + if (c == '(') { /* comments) */ 1.953 + int depth = 1; 1.954 + while (i < limit) { 1.955 + c = s[i]; 1.956 + i++; 1.957 + if (c == '(') depth++; 1.958 + else if (c == ')') 1.959 + if (--depth <= 0) 1.960 + break; 1.961 + } 1.962 + continue; 1.963 + } 1.964 + if ('0' <= c && c <= '9') { 1.965 + n = c - '0'; 1.966 + while (i < limit && '0' <= (c = s[i]) && c <= '9') { 1.967 + n = n * 10 + c - '0'; 1.968 + i++; 1.969 + } 1.970 + 1.971 + /* allow TZA before the year, so 1.972 + * 'Wed Nov 05 21:49:11 GMT-0800 1997' 1.973 + * works */ 1.974 + 1.975 + /* uses of seenplusminus allow : in TZA, so Java 1.976 + * no-timezone style of GMT+4:30 works 1.977 + */ 1.978 + 1.979 + if ((prevc == '+' || prevc == '-')/* && year>=0 */) { 1.980 + /* make ':' case below change tzoffset */ 1.981 + seenplusminus = true; 1.982 + 1.983 + /* offset */ 1.984 + if (n < 24) 1.985 + n = n * 60; /* EG. "GMT-3" */ 1.986 + else 1.987 + n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */ 1.988 + if (prevc == '+') /* plus means east of GMT */ 1.989 + n = -n; 1.990 + if (tzoffset != 0 && tzoffset != -1) 1.991 + goto syntax; 1.992 + tzoffset = n; 1.993 + } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) { 1.994 + if (c <= ' ' || c == ',' || c == '/' || i >= limit) 1.995 + year = n; 1.996 + else 1.997 + goto syntax; 1.998 + } else if (c == ':') { 1.999 + if (hour < 0) 1.1000 + hour = /*byte*/ n; 1.1001 + else if (min < 0) 1.1002 + min = /*byte*/ n; 1.1003 + else 1.1004 + goto syntax; 1.1005 + } else if (c == '/') { 1.1006 + /* until it is determined that mon is the actual 1.1007 + month, keep it as 1-based rather than 0-based */ 1.1008 + if (mon < 0) 1.1009 + mon = /*byte*/ n; 1.1010 + else if (mday < 0) 1.1011 + mday = /*byte*/ n; 1.1012 + else 1.1013 + goto syntax; 1.1014 + } else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') { 1.1015 + goto syntax; 1.1016 + } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */ 1.1017 + if (tzoffset < 0) 1.1018 + tzoffset -= n; 1.1019 + else 1.1020 + tzoffset += n; 1.1021 + } else if (hour >= 0 && min < 0) { 1.1022 + min = /*byte*/ n; 1.1023 + } else if (prevc == ':' && min >= 0 && sec < 0) { 1.1024 + sec = /*byte*/ n; 1.1025 + } else if (mon < 0) { 1.1026 + mon = /*byte*/n; 1.1027 + } else if (mon >= 0 && mday < 0) { 1.1028 + mday = /*byte*/ n; 1.1029 + } else if (mon >= 0 && mday >= 0 && year < 0) { 1.1030 + year = n; 1.1031 + } else { 1.1032 + goto syntax; 1.1033 + } 1.1034 + prevc = 0; 1.1035 + } else if (c == '/' || c == ':' || c == '+' || c == '-') { 1.1036 + prevc = c; 1.1037 + } else { 1.1038 + size_t st = i - 1; 1.1039 + int k; 1.1040 + while (i < limit) { 1.1041 + c = s[i]; 1.1042 + if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) 1.1043 + break; 1.1044 + i++; 1.1045 + } 1.1046 + if (i <= st + 1) 1.1047 + goto syntax; 1.1048 + for (k = ArrayLength(wtb); --k >= 0;) 1.1049 + if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) { 1.1050 + int action = ttb[k]; 1.1051 + if (action != 0) { 1.1052 + if (action < 0) { 1.1053 + /* 1.1054 + * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as 1.1055 + * 12:30, instead of blindly adding 12 if PM. 1.1056 + */ 1.1057 + JS_ASSERT(action == -1 || action == -2); 1.1058 + if (hour > 12 || hour < 0) { 1.1059 + goto syntax; 1.1060 + } else { 1.1061 + if (action == -1 && hour == 12) { /* am */ 1.1062 + hour = 0; 1.1063 + } else if (action == -2 && hour != 12) { /* pm */ 1.1064 + hour += 12; 1.1065 + } 1.1066 + } 1.1067 + } else if (action <= 13) { /* month! */ 1.1068 + /* Adjust mon to be 1-based until the final values 1.1069 + for mon, mday and year are adjusted below */ 1.1070 + if (seenmonthname) { 1.1071 + goto syntax; 1.1072 + } 1.1073 + seenmonthname = true; 1.1074 + temp = /*byte*/ (action - 2) + 1; 1.1075 + 1.1076 + if (mon < 0) { 1.1077 + mon = temp; 1.1078 + } else if (mday < 0) { 1.1079 + mday = mon; 1.1080 + mon = temp; 1.1081 + } else if (year < 0) { 1.1082 + year = mon; 1.1083 + mon = temp; 1.1084 + } else { 1.1085 + goto syntax; 1.1086 + } 1.1087 + } else { 1.1088 + tzoffset = action - 10000; 1.1089 + } 1.1090 + } 1.1091 + break; 1.1092 + } 1.1093 + if (k < 0) 1.1094 + goto syntax; 1.1095 + prevc = 0; 1.1096 + } 1.1097 + } 1.1098 + if (year < 0 || mon < 0 || mday < 0) 1.1099 + goto syntax; 1.1100 + /* 1.1101 + Case 1. The input string contains an English month name. 1.1102 + The form of the string can be month f l, or f month l, or 1.1103 + f l month which each evaluate to the same date. 1.1104 + If f and l are both greater than or equal to 70, or 1.1105 + both less than 70, the date is invalid. 1.1106 + The year is taken to be the greater of the values f, l. 1.1107 + If the year is greater than or equal to 70 and less than 100, 1.1108 + it is considered to be the number of years after 1900. 1.1109 + Case 2. The input string is of the form "f/m/l" where f, m and l are 1.1110 + integers, e.g. 7/16/45. 1.1111 + Adjust the mon, mday and year values to achieve 100% MSIE 1.1112 + compatibility. 1.1113 + a. If 0 <= f < 70, f/m/l is interpreted as month/day/year. 1.1114 + i. If year < 100, it is the number of years after 1900 1.1115 + ii. If year >= 100, it is the number of years after 0. 1.1116 + b. If 70 <= f < 100 1.1117 + i. If m < 70, f/m/l is interpreted as 1.1118 + year/month/day where year is the number of years after 1.1119 + 1900. 1.1120 + ii. If m >= 70, the date is invalid. 1.1121 + c. If f >= 100 1.1122 + i. If m < 70, f/m/l is interpreted as 1.1123 + year/month/day where year is the number of years after 0. 1.1124 + ii. If m >= 70, the date is invalid. 1.1125 + */ 1.1126 + if (seenmonthname) { 1.1127 + if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) { 1.1128 + goto syntax; 1.1129 + } 1.1130 + if (mday > year) { 1.1131 + temp = year; 1.1132 + year = mday; 1.1133 + mday = temp; 1.1134 + } 1.1135 + if (year >= 70 && year < 100) { 1.1136 + year += 1900; 1.1137 + } 1.1138 + } else if (mon < 70) { /* (a) month/day/year */ 1.1139 + if (year < 100) { 1.1140 + year += 1900; 1.1141 + } 1.1142 + } else if (mon < 100) { /* (b) year/month/day */ 1.1143 + if (mday < 70) { 1.1144 + temp = year; 1.1145 + year = mon + 1900; 1.1146 + mon = mday; 1.1147 + mday = temp; 1.1148 + } else { 1.1149 + goto syntax; 1.1150 + } 1.1151 + } else { /* (c) year/month/day */ 1.1152 + if (mday < 70) { 1.1153 + temp = year; 1.1154 + year = mon; 1.1155 + mon = mday; 1.1156 + mday = temp; 1.1157 + } else { 1.1158 + goto syntax; 1.1159 + } 1.1160 + } 1.1161 + mon -= 1; /* convert month to 0-based */ 1.1162 + if (sec < 0) 1.1163 + sec = 0; 1.1164 + if (min < 0) 1.1165 + min = 0; 1.1166 + if (hour < 0) 1.1167 + hour = 0; 1.1168 + 1.1169 + msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0); 1.1170 + 1.1171 + if (tzoffset == -1) { /* no time zone specified, have to use local */ 1.1172 + msec = UTC(msec, dtInfo); 1.1173 + } else { 1.1174 + msec += tzoffset * msPerMinute; 1.1175 + } 1.1176 + 1.1177 + *result = msec; 1.1178 + return true; 1.1179 + 1.1180 +syntax: 1.1181 + /* syntax error */ 1.1182 + *result = 0; 1.1183 + return false; 1.1184 +} 1.1185 + 1.1186 +static bool 1.1187 +date_parse(JSContext *cx, unsigned argc, Value *vp) 1.1188 +{ 1.1189 + CallArgs args = CallArgsFromVp(argc, vp); 1.1190 + if (args.length() == 0) { 1.1191 + args.rval().setNaN(); 1.1192 + return true; 1.1193 + } 1.1194 + 1.1195 + JSString *str = ToString<CanGC>(cx, args[0]); 1.1196 + if (!str) 1.1197 + return false; 1.1198 + 1.1199 + JSLinearString *linearStr = str->ensureLinear(cx); 1.1200 + if (!linearStr) 1.1201 + return false; 1.1202 + 1.1203 + double result; 1.1204 + if (!date_parseString(linearStr, &result, &cx->runtime()->dateTimeInfo)) { 1.1205 + args.rval().setNaN(); 1.1206 + return true; 1.1207 + } 1.1208 + 1.1209 + result = TimeClip(result); 1.1210 + args.rval().setNumber(result); 1.1211 + return true; 1.1212 +} 1.1213 + 1.1214 +static inline double 1.1215 +NowAsMillis() 1.1216 +{ 1.1217 + return (double) (PRMJ_Now() / PRMJ_USEC_PER_MSEC); 1.1218 +} 1.1219 + 1.1220 +static bool 1.1221 +date_now(JSContext *cx, unsigned argc, Value *vp) 1.1222 +{ 1.1223 + CallArgs args = CallArgsFromVp(argc, vp); 1.1224 + args.rval().setDouble(NowAsMillis()); 1.1225 + return true; 1.1226 +} 1.1227 + 1.1228 +void 1.1229 +DateObject::setUTCTime(double t, Value *vp) 1.1230 +{ 1.1231 + for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++) 1.1232 + setReservedSlot(ind, UndefinedValue()); 1.1233 + 1.1234 + setFixedSlot(UTC_TIME_SLOT, DoubleValue(t)); 1.1235 + if (vp) 1.1236 + vp->setDouble(t); 1.1237 +} 1.1238 + 1.1239 +void 1.1240 +DateObject::fillLocalTimeSlots(DateTimeInfo *dtInfo) 1.1241 +{ 1.1242 + /* Check if the cache is already populated. */ 1.1243 + if (!getReservedSlot(LOCAL_TIME_SLOT).isUndefined() && 1.1244 + getReservedSlot(TZA_SLOT).toDouble() == dtInfo->localTZA()) 1.1245 + { 1.1246 + return; 1.1247 + } 1.1248 + 1.1249 + /* Remember timezone used to generate the local cache. */ 1.1250 + setReservedSlot(TZA_SLOT, DoubleValue(dtInfo->localTZA())); 1.1251 + 1.1252 + double utcTime = UTCTime().toNumber(); 1.1253 + 1.1254 + if (!IsFinite(utcTime)) { 1.1255 + for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++) 1.1256 + setReservedSlot(ind, DoubleValue(utcTime)); 1.1257 + return; 1.1258 + } 1.1259 + 1.1260 + double localTime = LocalTime(utcTime, dtInfo); 1.1261 + 1.1262 + setReservedSlot(LOCAL_TIME_SLOT, DoubleValue(localTime)); 1.1263 + 1.1264 + int year = (int) floor(localTime /(msPerDay * 365.2425)) + 1970; 1.1265 + double yearStartTime = TimeFromYear(year); 1.1266 + 1.1267 + /* Adjust the year in case the approximation was wrong, as in YearFromTime. */ 1.1268 + int yearDays; 1.1269 + if (yearStartTime > localTime) { 1.1270 + year--; 1.1271 + yearStartTime -= (msPerDay * DaysInYear(year)); 1.1272 + yearDays = DaysInYear(year); 1.1273 + } else { 1.1274 + yearDays = DaysInYear(year); 1.1275 + double nextStart = yearStartTime + (msPerDay * yearDays); 1.1276 + if (nextStart <= localTime) { 1.1277 + year++; 1.1278 + yearStartTime = nextStart; 1.1279 + yearDays = DaysInYear(year); 1.1280 + } 1.1281 + } 1.1282 + 1.1283 + setReservedSlot(LOCAL_YEAR_SLOT, Int32Value(year)); 1.1284 + 1.1285 + uint64_t yearTime = uint64_t(localTime - yearStartTime); 1.1286 + int yearSeconds = uint32_t(yearTime / 1000); 1.1287 + 1.1288 + int day = yearSeconds / int(SecondsPerDay); 1.1289 + 1.1290 + int step = -1, next = 30; 1.1291 + int month; 1.1292 + 1.1293 + do { 1.1294 + if (day <= next) { 1.1295 + month = 0; 1.1296 + break; 1.1297 + } 1.1298 + step = next; 1.1299 + next += ((yearDays == 366) ? 29 : 28); 1.1300 + if (day <= next) { 1.1301 + month = 1; 1.1302 + break; 1.1303 + } 1.1304 + step = next; 1.1305 + if (day <= (next += 31)) { 1.1306 + month = 2; 1.1307 + break; 1.1308 + } 1.1309 + step = next; 1.1310 + if (day <= (next += 30)) { 1.1311 + month = 3; 1.1312 + break; 1.1313 + } 1.1314 + step = next; 1.1315 + if (day <= (next += 31)) { 1.1316 + month = 4; 1.1317 + break; 1.1318 + } 1.1319 + step = next; 1.1320 + if (day <= (next += 30)) { 1.1321 + month = 5; 1.1322 + break; 1.1323 + } 1.1324 + step = next; 1.1325 + if (day <= (next += 31)) { 1.1326 + month = 6; 1.1327 + break; 1.1328 + } 1.1329 + step = next; 1.1330 + if (day <= (next += 31)) { 1.1331 + month = 7; 1.1332 + break; 1.1333 + } 1.1334 + step = next; 1.1335 + if (day <= (next += 30)) { 1.1336 + month = 8; 1.1337 + break; 1.1338 + } 1.1339 + step = next; 1.1340 + if (day <= (next += 31)) { 1.1341 + month = 9; 1.1342 + break; 1.1343 + } 1.1344 + step = next; 1.1345 + if (day <= (next += 30)) { 1.1346 + month = 10; 1.1347 + break; 1.1348 + } 1.1349 + step = next; 1.1350 + month = 11; 1.1351 + } while (0); 1.1352 + 1.1353 + setReservedSlot(LOCAL_MONTH_SLOT, Int32Value(month)); 1.1354 + setReservedSlot(LOCAL_DATE_SLOT, Int32Value(day - step)); 1.1355 + 1.1356 + int weekday = WeekDay(localTime); 1.1357 + setReservedSlot(LOCAL_DAY_SLOT, Int32Value(weekday)); 1.1358 + 1.1359 + int seconds = yearSeconds % 60; 1.1360 + setReservedSlot(LOCAL_SECONDS_SLOT, Int32Value(seconds)); 1.1361 + 1.1362 + int minutes = (yearSeconds / 60) % 60; 1.1363 + setReservedSlot(LOCAL_MINUTES_SLOT, Int32Value(minutes)); 1.1364 + 1.1365 + int hours = (yearSeconds / (60 * 60)) % 24; 1.1366 + setReservedSlot(LOCAL_HOURS_SLOT, Int32Value(hours)); 1.1367 +} 1.1368 + 1.1369 +inline double 1.1370 +DateObject::cachedLocalTime(DateTimeInfo *dtInfo) 1.1371 +{ 1.1372 + fillLocalTimeSlots(dtInfo); 1.1373 + return getReservedSlot(LOCAL_TIME_SLOT).toDouble(); 1.1374 +} 1.1375 + 1.1376 +MOZ_ALWAYS_INLINE bool 1.1377 +IsDate(HandleValue v) 1.1378 +{ 1.1379 + return v.isObject() && v.toObject().is<DateObject>(); 1.1380 +} 1.1381 + 1.1382 +/* 1.1383 + * See ECMA 15.9.5.4 thru 15.9.5.23 1.1384 + */ 1.1385 +/* static */ MOZ_ALWAYS_INLINE bool 1.1386 +DateObject::getTime_impl(JSContext *cx, CallArgs args) 1.1387 +{ 1.1388 + args.rval().set(args.thisv().toObject().as<DateObject>().UTCTime()); 1.1389 + return true; 1.1390 +} 1.1391 + 1.1392 +static bool 1.1393 +date_getTime(JSContext *cx, unsigned argc, Value *vp) 1.1394 +{ 1.1395 + CallArgs args = CallArgsFromVp(argc, vp); 1.1396 + return CallNonGenericMethod<IsDate, DateObject::getTime_impl>(cx, args); 1.1397 +} 1.1398 + 1.1399 +/* static */ MOZ_ALWAYS_INLINE bool 1.1400 +DateObject::getYear_impl(JSContext *cx, CallArgs args) 1.1401 +{ 1.1402 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1403 + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); 1.1404 + 1.1405 + Value yearVal = dateObj->getReservedSlot(LOCAL_YEAR_SLOT); 1.1406 + if (yearVal.isInt32()) { 1.1407 + /* Follow ECMA-262 to the letter, contrary to IE JScript. */ 1.1408 + int year = yearVal.toInt32() - 1900; 1.1409 + args.rval().setInt32(year); 1.1410 + } else { 1.1411 + args.rval().set(yearVal); 1.1412 + } 1.1413 + 1.1414 + return true; 1.1415 +} 1.1416 + 1.1417 +static bool 1.1418 +date_getYear(JSContext *cx, unsigned argc, Value *vp) 1.1419 +{ 1.1420 + CallArgs args = CallArgsFromVp(argc, vp); 1.1421 + return CallNonGenericMethod<IsDate, DateObject::getYear_impl>(cx, args); 1.1422 +} 1.1423 + 1.1424 +/* static */ MOZ_ALWAYS_INLINE bool 1.1425 +DateObject::getFullYear_impl(JSContext *cx, CallArgs args) 1.1426 +{ 1.1427 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1428 + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); 1.1429 + 1.1430 + args.rval().set(dateObj->getReservedSlot(LOCAL_YEAR_SLOT)); 1.1431 + return true; 1.1432 +} 1.1433 + 1.1434 +static bool 1.1435 +date_getFullYear(JSContext *cx, unsigned argc, Value *vp) 1.1436 +{ 1.1437 + CallArgs args = CallArgsFromVp(argc, vp); 1.1438 + return CallNonGenericMethod<IsDate, DateObject::getFullYear_impl>(cx, args); 1.1439 +} 1.1440 + 1.1441 +/* static */ MOZ_ALWAYS_INLINE bool 1.1442 +DateObject::getUTCFullYear_impl(JSContext *cx, CallArgs args) 1.1443 +{ 1.1444 + double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.1445 + if (IsFinite(result)) 1.1446 + result = YearFromTime(result); 1.1447 + 1.1448 + args.rval().setNumber(result); 1.1449 + return true; 1.1450 +} 1.1451 + 1.1452 +static bool 1.1453 +date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp) 1.1454 +{ 1.1455 + CallArgs args = CallArgsFromVp(argc, vp); 1.1456 + return CallNonGenericMethod<IsDate, DateObject::getUTCFullYear_impl>(cx, args); 1.1457 +} 1.1458 + 1.1459 +/* static */ MOZ_ALWAYS_INLINE bool 1.1460 +DateObject::getMonth_impl(JSContext *cx, CallArgs args) 1.1461 +{ 1.1462 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1463 + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); 1.1464 + 1.1465 + args.rval().set(dateObj->getReservedSlot(LOCAL_MONTH_SLOT)); 1.1466 + return true; 1.1467 +} 1.1468 + 1.1469 +static bool 1.1470 +date_getMonth(JSContext *cx, unsigned argc, Value *vp) 1.1471 +{ 1.1472 + CallArgs args = CallArgsFromVp(argc, vp); 1.1473 + return CallNonGenericMethod<IsDate, DateObject::getMonth_impl>(cx, args); 1.1474 +} 1.1475 + 1.1476 +/* static */ MOZ_ALWAYS_INLINE bool 1.1477 +DateObject::getUTCMonth_impl(JSContext *cx, CallArgs args) 1.1478 +{ 1.1479 + double d = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.1480 + args.rval().setNumber(MonthFromTime(d)); 1.1481 + return true; 1.1482 +} 1.1483 + 1.1484 +static bool 1.1485 +date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp) 1.1486 +{ 1.1487 + CallArgs args = CallArgsFromVp(argc, vp); 1.1488 + return CallNonGenericMethod<IsDate, DateObject::getUTCMonth_impl>(cx, args); 1.1489 +} 1.1490 + 1.1491 +/* static */ MOZ_ALWAYS_INLINE bool 1.1492 +DateObject::getDate_impl(JSContext *cx, CallArgs args) 1.1493 +{ 1.1494 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1495 + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); 1.1496 + 1.1497 + args.rval().set(dateObj->getReservedSlot(LOCAL_DATE_SLOT)); 1.1498 + return true; 1.1499 +} 1.1500 + 1.1501 +static bool 1.1502 +date_getDate(JSContext *cx, unsigned argc, Value *vp) 1.1503 +{ 1.1504 + CallArgs args = CallArgsFromVp(argc, vp); 1.1505 + return CallNonGenericMethod<IsDate, DateObject::getDate_impl>(cx, args); 1.1506 +} 1.1507 + 1.1508 +/* static */ MOZ_ALWAYS_INLINE bool 1.1509 +DateObject::getUTCDate_impl(JSContext *cx, CallArgs args) 1.1510 +{ 1.1511 + double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.1512 + if (IsFinite(result)) 1.1513 + result = DateFromTime(result); 1.1514 + 1.1515 + args.rval().setNumber(result); 1.1516 + return true; 1.1517 +} 1.1518 + 1.1519 +static bool 1.1520 +date_getUTCDate(JSContext *cx, unsigned argc, Value *vp) 1.1521 +{ 1.1522 + CallArgs args = CallArgsFromVp(argc, vp); 1.1523 + return CallNonGenericMethod<IsDate, DateObject::getUTCDate_impl>(cx, args); 1.1524 +} 1.1525 + 1.1526 +/* static */ MOZ_ALWAYS_INLINE bool 1.1527 +DateObject::getDay_impl(JSContext *cx, CallArgs args) 1.1528 +{ 1.1529 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1530 + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); 1.1531 + 1.1532 + args.rval().set(dateObj->getReservedSlot(LOCAL_DAY_SLOT)); 1.1533 + return true; 1.1534 +} 1.1535 + 1.1536 +static bool 1.1537 +date_getDay(JSContext *cx, unsigned argc, Value *vp) 1.1538 +{ 1.1539 + CallArgs args = CallArgsFromVp(argc, vp); 1.1540 + return CallNonGenericMethod<IsDate, DateObject::getDay_impl>(cx, args); 1.1541 +} 1.1542 + 1.1543 +/* static */ MOZ_ALWAYS_INLINE bool 1.1544 +DateObject::getUTCDay_impl(JSContext *cx, CallArgs args) 1.1545 +{ 1.1546 + double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.1547 + if (IsFinite(result)) 1.1548 + result = WeekDay(result); 1.1549 + 1.1550 + args.rval().setNumber(result); 1.1551 + return true; 1.1552 +} 1.1553 + 1.1554 +static bool 1.1555 +date_getUTCDay(JSContext *cx, unsigned argc, Value *vp) 1.1556 +{ 1.1557 + CallArgs args = CallArgsFromVp(argc, vp); 1.1558 + return CallNonGenericMethod<IsDate, DateObject::getUTCDay_impl>(cx, args); 1.1559 +} 1.1560 + 1.1561 +/* static */ MOZ_ALWAYS_INLINE bool 1.1562 +DateObject::getHours_impl(JSContext *cx, CallArgs args) 1.1563 +{ 1.1564 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1565 + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); 1.1566 + 1.1567 + args.rval().set(dateObj->getReservedSlot(LOCAL_HOURS_SLOT)); 1.1568 + return true; 1.1569 +} 1.1570 + 1.1571 +static bool 1.1572 +date_getHours(JSContext *cx, unsigned argc, Value *vp) 1.1573 +{ 1.1574 + CallArgs args = CallArgsFromVp(argc, vp); 1.1575 + return CallNonGenericMethod<IsDate, DateObject::getHours_impl>(cx, args); 1.1576 +} 1.1577 + 1.1578 +/* static */ MOZ_ALWAYS_INLINE bool 1.1579 +DateObject::getUTCHours_impl(JSContext *cx, CallArgs args) 1.1580 +{ 1.1581 + double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.1582 + if (IsFinite(result)) 1.1583 + result = HourFromTime(result); 1.1584 + 1.1585 + args.rval().setNumber(result); 1.1586 + return true; 1.1587 +} 1.1588 + 1.1589 +static bool 1.1590 +date_getUTCHours(JSContext *cx, unsigned argc, Value *vp) 1.1591 +{ 1.1592 + CallArgs args = CallArgsFromVp(argc, vp); 1.1593 + return CallNonGenericMethod<IsDate, DateObject::getUTCHours_impl>(cx, args); 1.1594 +} 1.1595 + 1.1596 +/* static */ MOZ_ALWAYS_INLINE bool 1.1597 +DateObject::getMinutes_impl(JSContext *cx, CallArgs args) 1.1598 +{ 1.1599 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1600 + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); 1.1601 + 1.1602 + args.rval().set(dateObj->getReservedSlot(LOCAL_MINUTES_SLOT)); 1.1603 + return true; 1.1604 +} 1.1605 + 1.1606 +static bool 1.1607 +date_getMinutes(JSContext *cx, unsigned argc, Value *vp) 1.1608 +{ 1.1609 + CallArgs args = CallArgsFromVp(argc, vp); 1.1610 + return CallNonGenericMethod<IsDate, DateObject::getMinutes_impl>(cx, args); 1.1611 +} 1.1612 + 1.1613 +/* static */ MOZ_ALWAYS_INLINE bool 1.1614 +DateObject::getUTCMinutes_impl(JSContext *cx, CallArgs args) 1.1615 +{ 1.1616 + double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.1617 + if (IsFinite(result)) 1.1618 + result = MinFromTime(result); 1.1619 + 1.1620 + args.rval().setNumber(result); 1.1621 + return true; 1.1622 +} 1.1623 + 1.1624 +static bool 1.1625 +date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp) 1.1626 +{ 1.1627 + CallArgs args = CallArgsFromVp(argc, vp); 1.1628 + return CallNonGenericMethod<IsDate, DateObject::getUTCMinutes_impl>(cx, args); 1.1629 +} 1.1630 + 1.1631 +/* Date.getSeconds is mapped to getUTCSeconds */ 1.1632 + 1.1633 +/* static */ MOZ_ALWAYS_INLINE bool 1.1634 +DateObject::getUTCSeconds_impl(JSContext *cx, CallArgs args) 1.1635 +{ 1.1636 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1637 + dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo); 1.1638 + 1.1639 + args.rval().set(dateObj->getReservedSlot(LOCAL_SECONDS_SLOT)); 1.1640 + return true; 1.1641 +} 1.1642 + 1.1643 +static bool 1.1644 +date_getUTCSeconds(JSContext *cx, unsigned argc, Value *vp) 1.1645 +{ 1.1646 + CallArgs args = CallArgsFromVp(argc, vp); 1.1647 + return CallNonGenericMethod<IsDate, DateObject::getUTCSeconds_impl>(cx, args); 1.1648 +} 1.1649 + 1.1650 +/* Date.getMilliseconds is mapped to getUTCMilliseconds */ 1.1651 + 1.1652 +/* static */ MOZ_ALWAYS_INLINE bool 1.1653 +DateObject::getUTCMilliseconds_impl(JSContext *cx, CallArgs args) 1.1654 +{ 1.1655 + double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.1656 + if (IsFinite(result)) 1.1657 + result = msFromTime(result); 1.1658 + 1.1659 + args.rval().setNumber(result); 1.1660 + return true; 1.1661 +} 1.1662 + 1.1663 +static bool 1.1664 +date_getUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp) 1.1665 +{ 1.1666 + CallArgs args = CallArgsFromVp(argc, vp); 1.1667 + return CallNonGenericMethod<IsDate, DateObject::getUTCMilliseconds_impl>(cx, args); 1.1668 +} 1.1669 + 1.1670 +/* static */ MOZ_ALWAYS_INLINE bool 1.1671 +DateObject::getTimezoneOffset_impl(JSContext *cx, CallArgs args) 1.1672 +{ 1.1673 + DateObject *dateObj = &args.thisv().toObject().as<DateObject>(); 1.1674 + double utctime = dateObj->UTCTime().toNumber(); 1.1675 + double localtime = dateObj->cachedLocalTime(&cx->runtime()->dateTimeInfo); 1.1676 + 1.1677 + /* 1.1678 + * Return the time zone offset in minutes for the current locale that is 1.1679 + * appropriate for this time. This value would be a constant except for 1.1680 + * daylight savings time. 1.1681 + */ 1.1682 + double result = (utctime - localtime) / msPerMinute; 1.1683 + args.rval().setNumber(result); 1.1684 + return true; 1.1685 +} 1.1686 + 1.1687 +static bool 1.1688 +date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp) 1.1689 +{ 1.1690 + CallArgs args = CallArgsFromVp(argc, vp); 1.1691 + return CallNonGenericMethod<IsDate, DateObject::getTimezoneOffset_impl>(cx, args); 1.1692 +} 1.1693 + 1.1694 +MOZ_ALWAYS_INLINE bool 1.1695 +date_setTime_impl(JSContext *cx, CallArgs args) 1.1696 +{ 1.1697 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.1698 + if (args.length() == 0) { 1.1699 + dateObj->setUTCTime(GenericNaN(), args.rval().address()); 1.1700 + return true; 1.1701 + } 1.1702 + 1.1703 + double result; 1.1704 + if (!ToNumber(cx, args[0], &result)) 1.1705 + return false; 1.1706 + 1.1707 + dateObj->setUTCTime(TimeClip(result), args.rval().address()); 1.1708 + return true; 1.1709 +} 1.1710 + 1.1711 +static bool 1.1712 +date_setTime(JSContext *cx, unsigned argc, Value *vp) 1.1713 +{ 1.1714 + CallArgs args = CallArgsFromVp(argc, vp); 1.1715 + return CallNonGenericMethod<IsDate, date_setTime_impl>(cx, args); 1.1716 +} 1.1717 + 1.1718 +static bool 1.1719 +GetMsecsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *millis) 1.1720 +{ 1.1721 + if (args.length() <= i) { 1.1722 + *millis = msFromTime(t); 1.1723 + return true; 1.1724 + } 1.1725 + return ToNumber(cx, args[i], millis); 1.1726 +} 1.1727 + 1.1728 +static bool 1.1729 +GetSecsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *sec) 1.1730 +{ 1.1731 + if (args.length() <= i) { 1.1732 + *sec = SecFromTime(t); 1.1733 + return true; 1.1734 + } 1.1735 + return ToNumber(cx, args[i], sec); 1.1736 +} 1.1737 + 1.1738 +static bool 1.1739 +GetMinsOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *mins) 1.1740 +{ 1.1741 + if (args.length() <= i) { 1.1742 + *mins = MinFromTime(t); 1.1743 + return true; 1.1744 + } 1.1745 + return ToNumber(cx, args[i], mins); 1.1746 +} 1.1747 + 1.1748 +/* ES5 15.9.5.28. */ 1.1749 +MOZ_ALWAYS_INLINE bool 1.1750 +date_setMilliseconds_impl(JSContext *cx, CallArgs args) 1.1751 +{ 1.1752 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.1753 + 1.1754 + /* Step 1. */ 1.1755 + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); 1.1756 + 1.1757 + /* Step 2. */ 1.1758 + double milli; 1.1759 + if (!ToNumber(cx, args.get(0), &milli)) 1.1760 + return false; 1.1761 + double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), milli); 1.1762 + 1.1763 + /* Step 3. */ 1.1764 + double u = TimeClip(UTC(MakeDate(Day(t), time), &cx->runtime()->dateTimeInfo)); 1.1765 + 1.1766 + /* Steps 4-5. */ 1.1767 + dateObj->setUTCTime(u, args.rval().address()); 1.1768 + return true; 1.1769 +} 1.1770 + 1.1771 +static bool 1.1772 +date_setMilliseconds(JSContext *cx, unsigned argc, Value *vp) 1.1773 +{ 1.1774 + CallArgs args = CallArgsFromVp(argc, vp); 1.1775 + return CallNonGenericMethod<IsDate, date_setMilliseconds_impl>(cx, args); 1.1776 +} 1.1777 + 1.1778 +/* ES5 15.9.5.29. */ 1.1779 +MOZ_ALWAYS_INLINE bool 1.1780 +date_setUTCMilliseconds_impl(JSContext *cx, CallArgs args) 1.1781 +{ 1.1782 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.1783 + 1.1784 + /* Step 1. */ 1.1785 + double t = dateObj->UTCTime().toNumber(); 1.1786 + 1.1787 + /* Step 2. */ 1.1788 + double milli; 1.1789 + if (!ToNumber(cx, args.get(0), &milli)) 1.1790 + return false; 1.1791 + double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), milli); 1.1792 + 1.1793 + /* Step 3. */ 1.1794 + double v = TimeClip(MakeDate(Day(t), time)); 1.1795 + 1.1796 + /* Steps 4-5. */ 1.1797 + dateObj->setUTCTime(v, args.rval().address()); 1.1798 + return true; 1.1799 +} 1.1800 + 1.1801 +static bool 1.1802 +date_setUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp) 1.1803 +{ 1.1804 + CallArgs args = CallArgsFromVp(argc, vp); 1.1805 + return CallNonGenericMethod<IsDate, date_setUTCMilliseconds_impl>(cx, args); 1.1806 +} 1.1807 + 1.1808 +/* ES5 15.9.5.30. */ 1.1809 +MOZ_ALWAYS_INLINE bool 1.1810 +date_setSeconds_impl(JSContext *cx, CallArgs args) 1.1811 +{ 1.1812 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.1813 + 1.1814 + /* Step 1. */ 1.1815 + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); 1.1816 + 1.1817 + /* Step 2. */ 1.1818 + double s; 1.1819 + if (!ToNumber(cx, args.get(0), &s)) 1.1820 + return false; 1.1821 + 1.1822 + /* Step 3. */ 1.1823 + double milli; 1.1824 + if (!GetMsecsOrDefault(cx, args, 1, t, &milli)) 1.1825 + return false; 1.1826 + 1.1827 + /* Step 4. */ 1.1828 + double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli)); 1.1829 + 1.1830 + /* Step 5. */ 1.1831 + double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo)); 1.1832 + 1.1833 + /* Steps 6-7. */ 1.1834 + dateObj->setUTCTime(u, args.rval().address()); 1.1835 + return true; 1.1836 +} 1.1837 + 1.1838 +/* ES5 15.9.5.31. */ 1.1839 +static bool 1.1840 +date_setSeconds(JSContext *cx, unsigned argc, Value *vp) 1.1841 +{ 1.1842 + CallArgs args = CallArgsFromVp(argc, vp); 1.1843 + return CallNonGenericMethod<IsDate, date_setSeconds_impl>(cx, args); 1.1844 +} 1.1845 + 1.1846 +MOZ_ALWAYS_INLINE bool 1.1847 +date_setUTCSeconds_impl(JSContext *cx, CallArgs args) 1.1848 +{ 1.1849 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.1850 + 1.1851 + /* Step 1. */ 1.1852 + double t = dateObj->UTCTime().toNumber(); 1.1853 + 1.1854 + /* Step 2. */ 1.1855 + double s; 1.1856 + if (!ToNumber(cx, args.get(0), &s)) 1.1857 + return false; 1.1858 + 1.1859 + /* Step 3. */ 1.1860 + double milli; 1.1861 + if (!GetMsecsOrDefault(cx, args, 1, t, &milli)) 1.1862 + return false; 1.1863 + 1.1864 + /* Step 4. */ 1.1865 + double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli)); 1.1866 + 1.1867 + /* Step 5. */ 1.1868 + double v = TimeClip(date); 1.1869 + 1.1870 + /* Steps 6-7. */ 1.1871 + dateObj->setUTCTime(v, args.rval().address()); 1.1872 + return true; 1.1873 +} 1.1874 + 1.1875 +/* ES5 15.9.5.32. */ 1.1876 +static bool 1.1877 +date_setUTCSeconds(JSContext *cx, unsigned argc, Value *vp) 1.1878 +{ 1.1879 + CallArgs args = CallArgsFromVp(argc, vp); 1.1880 + return CallNonGenericMethod<IsDate, date_setUTCSeconds_impl>(cx, args); 1.1881 +} 1.1882 + 1.1883 +MOZ_ALWAYS_INLINE bool 1.1884 +date_setMinutes_impl(JSContext *cx, CallArgs args) 1.1885 +{ 1.1886 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.1887 + 1.1888 + /* Step 1. */ 1.1889 + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); 1.1890 + 1.1891 + /* Step 2. */ 1.1892 + double m; 1.1893 + if (!ToNumber(cx, args.get(0), &m)) 1.1894 + return false; 1.1895 + 1.1896 + /* Step 3. */ 1.1897 + double s; 1.1898 + if (!GetSecsOrDefault(cx, args, 1, t, &s)) 1.1899 + return false; 1.1900 + 1.1901 + /* Step 4. */ 1.1902 + double milli; 1.1903 + if (!GetMsecsOrDefault(cx, args, 2, t, &milli)) 1.1904 + return false; 1.1905 + 1.1906 + /* Step 5. */ 1.1907 + double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli)); 1.1908 + 1.1909 + /* Step 6. */ 1.1910 + double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo)); 1.1911 + 1.1912 + /* Steps 7-8. */ 1.1913 + dateObj->setUTCTime(u, args.rval().address()); 1.1914 + return true; 1.1915 +} 1.1916 + 1.1917 +/* ES5 15.9.5.33. */ 1.1918 +static bool 1.1919 +date_setMinutes(JSContext *cx, unsigned argc, Value *vp) 1.1920 +{ 1.1921 + CallArgs args = CallArgsFromVp(argc, vp); 1.1922 + return CallNonGenericMethod<IsDate, date_setMinutes_impl>(cx, args); 1.1923 +} 1.1924 + 1.1925 +MOZ_ALWAYS_INLINE bool 1.1926 +date_setUTCMinutes_impl(JSContext *cx, CallArgs args) 1.1927 +{ 1.1928 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.1929 + 1.1930 + /* Step 1. */ 1.1931 + double t = dateObj->UTCTime().toNumber(); 1.1932 + 1.1933 + /* Step 2. */ 1.1934 + double m; 1.1935 + if (!ToNumber(cx, args.get(0), &m)) 1.1936 + return false; 1.1937 + 1.1938 + /* Step 3. */ 1.1939 + double s; 1.1940 + if (!GetSecsOrDefault(cx, args, 1, t, &s)) 1.1941 + return false; 1.1942 + 1.1943 + /* Step 4. */ 1.1944 + double milli; 1.1945 + if (!GetMsecsOrDefault(cx, args, 2, t, &milli)) 1.1946 + return false; 1.1947 + 1.1948 + /* Step 5. */ 1.1949 + double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli)); 1.1950 + 1.1951 + /* Step 6. */ 1.1952 + double v = TimeClip(date); 1.1953 + 1.1954 + /* Steps 7-8. */ 1.1955 + dateObj->setUTCTime(v, args.rval().address()); 1.1956 + return true; 1.1957 +} 1.1958 + 1.1959 +/* ES5 15.9.5.34. */ 1.1960 +static bool 1.1961 +date_setUTCMinutes(JSContext *cx, unsigned argc, Value *vp) 1.1962 +{ 1.1963 + CallArgs args = CallArgsFromVp(argc, vp); 1.1964 + return CallNonGenericMethod<IsDate, date_setUTCMinutes_impl>(cx, args); 1.1965 +} 1.1966 + 1.1967 +MOZ_ALWAYS_INLINE bool 1.1968 +date_setHours_impl(JSContext *cx, CallArgs args) 1.1969 +{ 1.1970 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.1971 + 1.1972 + /* Step 1. */ 1.1973 + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); 1.1974 + 1.1975 + /* Step 2. */ 1.1976 + double h; 1.1977 + if (!ToNumber(cx, args.get(0), &h)) 1.1978 + return false; 1.1979 + 1.1980 + /* Step 3. */ 1.1981 + double m; 1.1982 + if (!GetMinsOrDefault(cx, args, 1, t, &m)) 1.1983 + return false; 1.1984 + 1.1985 + /* Step 4. */ 1.1986 + double s; 1.1987 + if (!GetSecsOrDefault(cx, args, 2, t, &s)) 1.1988 + return false; 1.1989 + 1.1990 + /* Step 5. */ 1.1991 + double milli; 1.1992 + if (!GetMsecsOrDefault(cx, args, 3, t, &milli)) 1.1993 + return false; 1.1994 + 1.1995 + /* Step 6. */ 1.1996 + double date = MakeDate(Day(t), MakeTime(h, m, s, milli)); 1.1997 + 1.1998 + /* Step 6. */ 1.1999 + double u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo)); 1.2000 + 1.2001 + /* Steps 7-8. */ 1.2002 + dateObj->setUTCTime(u, args.rval().address()); 1.2003 + return true; 1.2004 +} 1.2005 + 1.2006 +/* ES5 15.9.5.35. */ 1.2007 +static bool 1.2008 +date_setHours(JSContext *cx, unsigned argc, Value *vp) 1.2009 +{ 1.2010 + CallArgs args = CallArgsFromVp(argc, vp); 1.2011 + return CallNonGenericMethod<IsDate, date_setHours_impl>(cx, args); 1.2012 +} 1.2013 + 1.2014 +MOZ_ALWAYS_INLINE bool 1.2015 +date_setUTCHours_impl(JSContext *cx, CallArgs args) 1.2016 +{ 1.2017 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2018 + 1.2019 + /* Step 1. */ 1.2020 + double t = dateObj->UTCTime().toNumber(); 1.2021 + 1.2022 + /* Step 2. */ 1.2023 + double h; 1.2024 + if (!ToNumber(cx, args.get(0), &h)) 1.2025 + return false; 1.2026 + 1.2027 + /* Step 3. */ 1.2028 + double m; 1.2029 + if (!GetMinsOrDefault(cx, args, 1, t, &m)) 1.2030 + return false; 1.2031 + 1.2032 + /* Step 4. */ 1.2033 + double s; 1.2034 + if (!GetSecsOrDefault(cx, args, 2, t, &s)) 1.2035 + return false; 1.2036 + 1.2037 + /* Step 5. */ 1.2038 + double milli; 1.2039 + if (!GetMsecsOrDefault(cx, args, 3, t, &milli)) 1.2040 + return false; 1.2041 + 1.2042 + /* Step 6. */ 1.2043 + double newDate = MakeDate(Day(t), MakeTime(h, m, s, milli)); 1.2044 + 1.2045 + /* Step 7. */ 1.2046 + double v = TimeClip(newDate); 1.2047 + 1.2048 + /* Steps 8-9. */ 1.2049 + dateObj->setUTCTime(v, args.rval().address()); 1.2050 + return true; 1.2051 +} 1.2052 + 1.2053 +/* ES5 15.9.5.36. */ 1.2054 +static bool 1.2055 +date_setUTCHours(JSContext *cx, unsigned argc, Value *vp) 1.2056 +{ 1.2057 + CallArgs args = CallArgsFromVp(argc, vp); 1.2058 + return CallNonGenericMethod<IsDate, date_setUTCHours_impl>(cx, args); 1.2059 +} 1.2060 + 1.2061 +MOZ_ALWAYS_INLINE bool 1.2062 +date_setDate_impl(JSContext *cx, CallArgs args) 1.2063 +{ 1.2064 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2065 + 1.2066 + /* Step 1. */ 1.2067 + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); 1.2068 + 1.2069 + /* Step 2. */ 1.2070 + double date; 1.2071 + if (!ToNumber(cx, args.get(0), &date)) 1.2072 + return false; 1.2073 + 1.2074 + /* Step 3. */ 1.2075 + double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)); 1.2076 + 1.2077 + /* Step 4. */ 1.2078 + double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo)); 1.2079 + 1.2080 + /* Steps 5-6. */ 1.2081 + dateObj->setUTCTime(u, args.rval().address()); 1.2082 + return true; 1.2083 +} 1.2084 + 1.2085 +/* ES5 15.9.5.37. */ 1.2086 +static bool 1.2087 +date_setDate(JSContext *cx, unsigned argc, Value *vp) 1.2088 +{ 1.2089 + CallArgs args = CallArgsFromVp(argc, vp); 1.2090 + return CallNonGenericMethod<IsDate, date_setDate_impl>(cx, args); 1.2091 +} 1.2092 + 1.2093 +MOZ_ALWAYS_INLINE bool 1.2094 +date_setUTCDate_impl(JSContext *cx, CallArgs args) 1.2095 +{ 1.2096 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2097 + 1.2098 + /* Step 1. */ 1.2099 + double t = dateObj->UTCTime().toNumber(); 1.2100 + 1.2101 + /* Step 2. */ 1.2102 + double date; 1.2103 + if (!ToNumber(cx, args.get(0), &date)) 1.2104 + return false; 1.2105 + 1.2106 + /* Step 3. */ 1.2107 + double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)); 1.2108 + 1.2109 + /* Step 4. */ 1.2110 + double v = TimeClip(newDate); 1.2111 + 1.2112 + /* Steps 5-6. */ 1.2113 + dateObj->setUTCTime(v, args.rval().address()); 1.2114 + return true; 1.2115 +} 1.2116 + 1.2117 +static bool 1.2118 +date_setUTCDate(JSContext *cx, unsigned argc, Value *vp) 1.2119 +{ 1.2120 + CallArgs args = CallArgsFromVp(argc, vp); 1.2121 + return CallNonGenericMethod<IsDate, date_setUTCDate_impl>(cx, args); 1.2122 +} 1.2123 + 1.2124 +static bool 1.2125 +GetDateOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *date) 1.2126 +{ 1.2127 + if (args.length() <= i) { 1.2128 + *date = DateFromTime(t); 1.2129 + return true; 1.2130 + } 1.2131 + return ToNumber(cx, args[i], date); 1.2132 +} 1.2133 + 1.2134 +static bool 1.2135 +GetMonthOrDefault(JSContext *cx, const CallArgs &args, unsigned i, double t, double *month) 1.2136 +{ 1.2137 + if (args.length() <= i) { 1.2138 + *month = MonthFromTime(t); 1.2139 + return true; 1.2140 + } 1.2141 + return ToNumber(cx, args[i], month); 1.2142 +} 1.2143 + 1.2144 +/* ES5 15.9.5.38. */ 1.2145 +MOZ_ALWAYS_INLINE bool 1.2146 +date_setMonth_impl(JSContext *cx, CallArgs args) 1.2147 +{ 1.2148 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2149 + 1.2150 + /* Step 1. */ 1.2151 + double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo); 1.2152 + 1.2153 + /* Step 2. */ 1.2154 + double m; 1.2155 + if (!ToNumber(cx, args.get(0), &m)) 1.2156 + return false; 1.2157 + 1.2158 + /* Step 3. */ 1.2159 + double date; 1.2160 + if (!GetDateOrDefault(cx, args, 1, t, &date)) 1.2161 + return false; 1.2162 + 1.2163 + /* Step 4. */ 1.2164 + double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t)); 1.2165 + 1.2166 + /* Step 5. */ 1.2167 + double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo)); 1.2168 + 1.2169 + /* Steps 6-7. */ 1.2170 + dateObj->setUTCTime(u, args.rval().address()); 1.2171 + return true; 1.2172 +} 1.2173 + 1.2174 +static bool 1.2175 +date_setMonth(JSContext *cx, unsigned argc, Value *vp) 1.2176 +{ 1.2177 + CallArgs args = CallArgsFromVp(argc, vp); 1.2178 + return CallNonGenericMethod<IsDate, date_setMonth_impl>(cx, args); 1.2179 +} 1.2180 + 1.2181 +/* ES5 15.9.5.39. */ 1.2182 +MOZ_ALWAYS_INLINE bool 1.2183 +date_setUTCMonth_impl(JSContext *cx, CallArgs args) 1.2184 +{ 1.2185 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2186 + 1.2187 + /* Step 1. */ 1.2188 + double t = dateObj->UTCTime().toNumber(); 1.2189 + 1.2190 + /* Step 2. */ 1.2191 + double m; 1.2192 + if (!ToNumber(cx, args.get(0), &m)) 1.2193 + return false; 1.2194 + 1.2195 + /* Step 3. */ 1.2196 + double date; 1.2197 + if (!GetDateOrDefault(cx, args, 1, t, &date)) 1.2198 + return false; 1.2199 + 1.2200 + /* Step 4. */ 1.2201 + double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t)); 1.2202 + 1.2203 + /* Step 5. */ 1.2204 + double v = TimeClip(newDate); 1.2205 + 1.2206 + /* Steps 6-7. */ 1.2207 + dateObj->setUTCTime(v, args.rval().address()); 1.2208 + return true; 1.2209 +} 1.2210 + 1.2211 +static bool 1.2212 +date_setUTCMonth(JSContext *cx, unsigned argc, Value *vp) 1.2213 +{ 1.2214 + CallArgs args = CallArgsFromVp(argc, vp); 1.2215 + return CallNonGenericMethod<IsDate, date_setUTCMonth_impl>(cx, args); 1.2216 +} 1.2217 + 1.2218 +static double 1.2219 +ThisLocalTimeOrZero(Handle<DateObject*> dateObj, DateTimeInfo *dtInfo) 1.2220 +{ 1.2221 + double t = dateObj->UTCTime().toNumber(); 1.2222 + if (IsNaN(t)) 1.2223 + return +0; 1.2224 + return LocalTime(t, dtInfo); 1.2225 +} 1.2226 + 1.2227 +static double 1.2228 +ThisUTCTimeOrZero(Handle<DateObject*> dateObj) 1.2229 +{ 1.2230 + double t = dateObj->as<DateObject>().UTCTime().toNumber(); 1.2231 + return IsNaN(t) ? +0 : t; 1.2232 +} 1.2233 + 1.2234 +/* ES5 15.9.5.40. */ 1.2235 +MOZ_ALWAYS_INLINE bool 1.2236 +date_setFullYear_impl(JSContext *cx, CallArgs args) 1.2237 +{ 1.2238 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2239 + 1.2240 + /* Step 1. */ 1.2241 + double t = ThisLocalTimeOrZero(dateObj, &cx->runtime()->dateTimeInfo); 1.2242 + 1.2243 + /* Step 2. */ 1.2244 + double y; 1.2245 + if (!ToNumber(cx, args.get(0), &y)) 1.2246 + return false; 1.2247 + 1.2248 + /* Step 3. */ 1.2249 + double m; 1.2250 + if (!GetMonthOrDefault(cx, args, 1, t, &m)) 1.2251 + return false; 1.2252 + 1.2253 + /* Step 4. */ 1.2254 + double date; 1.2255 + if (!GetDateOrDefault(cx, args, 2, t, &date)) 1.2256 + return false; 1.2257 + 1.2258 + /* Step 5. */ 1.2259 + double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t)); 1.2260 + 1.2261 + /* Step 6. */ 1.2262 + double u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo)); 1.2263 + 1.2264 + /* Steps 7-8. */ 1.2265 + dateObj->setUTCTime(u, args.rval().address()); 1.2266 + return true; 1.2267 +} 1.2268 + 1.2269 +static bool 1.2270 +date_setFullYear(JSContext *cx, unsigned argc, Value *vp) 1.2271 +{ 1.2272 + CallArgs args = CallArgsFromVp(argc, vp); 1.2273 + return CallNonGenericMethod<IsDate, date_setFullYear_impl>(cx, args); 1.2274 +} 1.2275 + 1.2276 +/* ES5 15.9.5.41. */ 1.2277 +MOZ_ALWAYS_INLINE bool 1.2278 +date_setUTCFullYear_impl(JSContext *cx, CallArgs args) 1.2279 +{ 1.2280 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2281 + 1.2282 + /* Step 1. */ 1.2283 + double t = ThisUTCTimeOrZero(dateObj); 1.2284 + 1.2285 + /* Step 2. */ 1.2286 + double y; 1.2287 + if (!ToNumber(cx, args.get(0), &y)) 1.2288 + return false; 1.2289 + 1.2290 + /* Step 3. */ 1.2291 + double m; 1.2292 + if (!GetMonthOrDefault(cx, args, 1, t, &m)) 1.2293 + return false; 1.2294 + 1.2295 + /* Step 4. */ 1.2296 + double date; 1.2297 + if (!GetDateOrDefault(cx, args, 2, t, &date)) 1.2298 + return false; 1.2299 + 1.2300 + /* Step 5. */ 1.2301 + double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t)); 1.2302 + 1.2303 + /* Step 6. */ 1.2304 + double v = TimeClip(newDate); 1.2305 + 1.2306 + /* Steps 7-8. */ 1.2307 + dateObj->setUTCTime(v, args.rval().address()); 1.2308 + return true; 1.2309 +} 1.2310 + 1.2311 +static bool 1.2312 +date_setUTCFullYear(JSContext *cx, unsigned argc, Value *vp) 1.2313 +{ 1.2314 + CallArgs args = CallArgsFromVp(argc, vp); 1.2315 + return CallNonGenericMethod<IsDate, date_setUTCFullYear_impl>(cx, args); 1.2316 +} 1.2317 + 1.2318 +/* ES5 Annex B.2.5. */ 1.2319 +MOZ_ALWAYS_INLINE bool 1.2320 +date_setYear_impl(JSContext *cx, CallArgs args) 1.2321 +{ 1.2322 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2323 + 1.2324 + /* Step 1. */ 1.2325 + double t = ThisLocalTimeOrZero(dateObj, &cx->runtime()->dateTimeInfo); 1.2326 + 1.2327 + /* Step 2. */ 1.2328 + double y; 1.2329 + if (!ToNumber(cx, args.get(0), &y)) 1.2330 + return false; 1.2331 + 1.2332 + /* Step 3. */ 1.2333 + if (IsNaN(y)) { 1.2334 + dateObj->setUTCTime(GenericNaN(), args.rval().address()); 1.2335 + return true; 1.2336 + } 1.2337 + 1.2338 + /* Step 4. */ 1.2339 + double yint = ToInteger(y); 1.2340 + if (0 <= yint && yint <= 99) 1.2341 + yint += 1900; 1.2342 + 1.2343 + /* Step 5. */ 1.2344 + double day = MakeDay(yint, MonthFromTime(t), DateFromTime(t)); 1.2345 + 1.2346 + /* Step 6. */ 1.2347 + double u = UTC(MakeDate(day, TimeWithinDay(t)), &cx->runtime()->dateTimeInfo); 1.2348 + 1.2349 + /* Steps 7-8. */ 1.2350 + dateObj->setUTCTime(TimeClip(u), args.rval().address()); 1.2351 + return true; 1.2352 +} 1.2353 + 1.2354 +static bool 1.2355 +date_setYear(JSContext *cx, unsigned argc, Value *vp) 1.2356 +{ 1.2357 + CallArgs args = CallArgsFromVp(argc, vp); 1.2358 + return CallNonGenericMethod<IsDate, date_setYear_impl>(cx, args); 1.2359 +} 1.2360 + 1.2361 +/* constants for toString, toUTCString */ 1.2362 +static const char js_NaN_date_str[] = "Invalid Date"; 1.2363 +static const char * const days[] = 1.2364 +{ 1.2365 + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" 1.2366 +}; 1.2367 +static const char * const months[] = 1.2368 +{ 1.2369 + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 1.2370 +}; 1.2371 + 1.2372 + 1.2373 +// Avoid dependence on PRMJ_FormatTimeUSEnglish, because it 1.2374 +// requires a PRMJTime... which only has 16-bit years. Sub-ECMA. 1.2375 +static void 1.2376 +print_gmt_string(char* buf, size_t size, double utctime) 1.2377 +{ 1.2378 + JS_ASSERT(TimeClip(utctime) == utctime); 1.2379 + JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", 1.2380 + days[int(WeekDay(utctime))], 1.2381 + int(DateFromTime(utctime)), 1.2382 + months[int(MonthFromTime(utctime))], 1.2383 + int(YearFromTime(utctime)), 1.2384 + int(HourFromTime(utctime)), 1.2385 + int(MinFromTime(utctime)), 1.2386 + int(SecFromTime(utctime))); 1.2387 +} 1.2388 + 1.2389 +static void 1.2390 +print_iso_string(char* buf, size_t size, double utctime) 1.2391 +{ 1.2392 + JS_ASSERT(TimeClip(utctime) == utctime); 1.2393 + JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ", 1.2394 + int(YearFromTime(utctime)), 1.2395 + int(MonthFromTime(utctime)) + 1, 1.2396 + int(DateFromTime(utctime)), 1.2397 + int(HourFromTime(utctime)), 1.2398 + int(MinFromTime(utctime)), 1.2399 + int(SecFromTime(utctime)), 1.2400 + int(msFromTime(utctime))); 1.2401 +} 1.2402 + 1.2403 +/* ES5 B.2.6. */ 1.2404 +MOZ_ALWAYS_INLINE bool 1.2405 +date_toGMTString_impl(JSContext *cx, CallArgs args) 1.2406 +{ 1.2407 + double utctime = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.2408 + 1.2409 + char buf[100]; 1.2410 + if (!IsFinite(utctime)) 1.2411 + JS_snprintf(buf, sizeof buf, js_NaN_date_str); 1.2412 + else 1.2413 + print_gmt_string(buf, sizeof buf, utctime); 1.2414 + 1.2415 + JSString *str = JS_NewStringCopyZ(cx, buf); 1.2416 + if (!str) 1.2417 + return false; 1.2418 + args.rval().setString(str); 1.2419 + return true; 1.2420 +} 1.2421 + 1.2422 +/* ES5 15.9.5.43. */ 1.2423 +static bool 1.2424 +date_toGMTString(JSContext *cx, unsigned argc, Value *vp) 1.2425 +{ 1.2426 + CallArgs args = CallArgsFromVp(argc, vp); 1.2427 + return CallNonGenericMethod<IsDate, date_toGMTString_impl>(cx, args); 1.2428 +} 1.2429 + 1.2430 +MOZ_ALWAYS_INLINE bool 1.2431 +date_toISOString_impl(JSContext *cx, CallArgs args) 1.2432 +{ 1.2433 + double utctime = args.thisv().toObject().as<DateObject>().UTCTime().toNumber(); 1.2434 + if (!IsFinite(utctime)) { 1.2435 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INVALID_DATE); 1.2436 + return false; 1.2437 + } 1.2438 + 1.2439 + char buf[100]; 1.2440 + print_iso_string(buf, sizeof buf, utctime); 1.2441 + 1.2442 + JSString *str = JS_NewStringCopyZ(cx, buf); 1.2443 + if (!str) 1.2444 + return false; 1.2445 + args.rval().setString(str); 1.2446 + return true; 1.2447 + 1.2448 +} 1.2449 + 1.2450 +static bool 1.2451 +date_toISOString(JSContext *cx, unsigned argc, Value *vp) 1.2452 +{ 1.2453 + CallArgs args = CallArgsFromVp(argc, vp); 1.2454 + return CallNonGenericMethod<IsDate, date_toISOString_impl>(cx, args); 1.2455 +} 1.2456 + 1.2457 +/* ES5 15.9.5.44. */ 1.2458 +static bool 1.2459 +date_toJSON(JSContext *cx, unsigned argc, Value *vp) 1.2460 +{ 1.2461 + CallArgs args = CallArgsFromVp(argc, vp); 1.2462 + 1.2463 + /* Step 1. */ 1.2464 + RootedObject obj(cx, ToObject(cx, args.thisv())); 1.2465 + if (!obj) 1.2466 + return false; 1.2467 + 1.2468 + /* Step 2. */ 1.2469 + RootedValue tv(cx, ObjectValue(*obj)); 1.2470 + if (!ToPrimitive(cx, JSTYPE_NUMBER, &tv)) 1.2471 + return false; 1.2472 + 1.2473 + /* Step 3. */ 1.2474 + if (tv.isDouble() && !IsFinite(tv.toDouble())) { 1.2475 + args.rval().setNull(); 1.2476 + return true; 1.2477 + } 1.2478 + 1.2479 + /* Step 4. */ 1.2480 + RootedValue toISO(cx); 1.2481 + if (!JSObject::getProperty(cx, obj, obj, cx->names().toISOString, &toISO)) 1.2482 + return false; 1.2483 + 1.2484 + /* Step 5. */ 1.2485 + if (!js_IsCallable(toISO)) { 1.2486 + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, nullptr, 1.2487 + JSMSG_BAD_TOISOSTRING_PROP); 1.2488 + return false; 1.2489 + } 1.2490 + 1.2491 + /* Step 6. */ 1.2492 + InvokeArgs args2(cx); 1.2493 + if (!args2.init(0)) 1.2494 + return false; 1.2495 + 1.2496 + args2.setCallee(toISO); 1.2497 + args2.setThis(ObjectValue(*obj)); 1.2498 + 1.2499 + if (!Invoke(cx, args2)) 1.2500 + return false; 1.2501 + args.rval().set(args2.rval()); 1.2502 + return true; 1.2503 +} 1.2504 + 1.2505 +/* for Date.toLocaleFormat; interface to PRMJTime date struct. 1.2506 + */ 1.2507 +static void 1.2508 +new_explode(double timeval, PRMJTime *split, DateTimeInfo *dtInfo) 1.2509 +{ 1.2510 + double year = YearFromTime(timeval); 1.2511 + 1.2512 + split->tm_usec = int32_t(msFromTime(timeval)) * 1000; 1.2513 + split->tm_sec = int8_t(SecFromTime(timeval)); 1.2514 + split->tm_min = int8_t(MinFromTime(timeval)); 1.2515 + split->tm_hour = int8_t(HourFromTime(timeval)); 1.2516 + split->tm_mday = int8_t(DateFromTime(timeval)); 1.2517 + split->tm_mon = int8_t(MonthFromTime(timeval)); 1.2518 + split->tm_wday = int8_t(WeekDay(timeval)); 1.2519 + split->tm_year = year; 1.2520 + split->tm_yday = int16_t(DayWithinYear(timeval, year)); 1.2521 + 1.2522 + /* not sure how this affects things, but it doesn't seem 1.2523 + to matter. */ 1.2524 + split->tm_isdst = (DaylightSavingTA(timeval, dtInfo) != 0); 1.2525 +} 1.2526 + 1.2527 +typedef enum formatspec { 1.2528 + FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME 1.2529 +} formatspec; 1.2530 + 1.2531 +/* helper function */ 1.2532 +static bool 1.2533 +date_format(JSContext *cx, double date, formatspec format, MutableHandleValue rval) 1.2534 +{ 1.2535 + char buf[100]; 1.2536 + char tzbuf[100]; 1.2537 + bool usetz; 1.2538 + size_t i, tzlen; 1.2539 + PRMJTime split; 1.2540 + 1.2541 + if (!IsFinite(date)) { 1.2542 + JS_snprintf(buf, sizeof buf, js_NaN_date_str); 1.2543 + } else { 1.2544 + JS_ASSERT(TimeClip(date) == date); 1.2545 + 1.2546 + double local = LocalTime(date, &cx->runtime()->dateTimeInfo); 1.2547 + 1.2548 + /* offset from GMT in minutes. The offset includes daylight savings, 1.2549 + if it applies. */ 1.2550 + int minutes = (int) floor(AdjustTime(date, &cx->runtime()->dateTimeInfo) / msPerMinute); 1.2551 + 1.2552 + /* map 510 minutes to 0830 hours */ 1.2553 + int offset = (minutes / 60) * 100 + minutes % 60; 1.2554 + 1.2555 + /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is 1.2556 + * printed as 'GMT-0800' rather than as 'PST' to avoid 1.2557 + * operating-system dependence on strftime (which 1.2558 + * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints 1.2559 + * PST as 'Pacific Standard Time.' This way we always know 1.2560 + * what we're getting, and can parse it if we produce it. 1.2561 + * The OS TZA string is included as a comment. 1.2562 + */ 1.2563 + 1.2564 + /* get a timezone string from the OS to include as a 1.2565 + comment. */ 1.2566 + new_explode(date, &split, &cx->runtime()->dateTimeInfo); 1.2567 + if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) { 1.2568 + 1.2569 + /* Decide whether to use the resulting timezone string. 1.2570 + * 1.2571 + * Reject it if it contains any non-ASCII, non-alphanumeric 1.2572 + * characters. It's then likely in some other character 1.2573 + * encoding, and we probably won't display it correctly. 1.2574 + */ 1.2575 + usetz = true; 1.2576 + tzlen = strlen(tzbuf); 1.2577 + if (tzlen > 100) { 1.2578 + usetz = false; 1.2579 + } else { 1.2580 + for (i = 0; i < tzlen; i++) { 1.2581 + jschar c = tzbuf[i]; 1.2582 + if (c > 127 || 1.2583 + !(isalpha(c) || isdigit(c) || 1.2584 + c == ' ' || c == '(' || c == ')')) { 1.2585 + usetz = false; 1.2586 + } 1.2587 + } 1.2588 + } 1.2589 + 1.2590 + /* Also reject it if it's not parenthesized or if it's '()'. */ 1.2591 + if (tzbuf[0] != '(' || tzbuf[1] == ')') 1.2592 + usetz = false; 1.2593 + } else 1.2594 + usetz = false; 1.2595 + 1.2596 + switch (format) { 1.2597 + case FORMATSPEC_FULL: 1.2598 + /* 1.2599 + * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it 1.2600 + * requires a PRMJTime... which only has 16-bit years. Sub-ECMA. 1.2601 + */ 1.2602 + /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */ 1.2603 + JS_snprintf(buf, sizeof buf, 1.2604 + "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s", 1.2605 + days[int(WeekDay(local))], 1.2606 + months[int(MonthFromTime(local))], 1.2607 + int(DateFromTime(local)), 1.2608 + int(YearFromTime(local)), 1.2609 + int(HourFromTime(local)), 1.2610 + int(MinFromTime(local)), 1.2611 + int(SecFromTime(local)), 1.2612 + offset, 1.2613 + usetz ? " " : "", 1.2614 + usetz ? tzbuf : ""); 1.2615 + break; 1.2616 + case FORMATSPEC_DATE: 1.2617 + /* Tue Oct 31 2000 */ 1.2618 + JS_snprintf(buf, sizeof buf, 1.2619 + "%s %s %.2d %.4d", 1.2620 + days[int(WeekDay(local))], 1.2621 + months[int(MonthFromTime(local))], 1.2622 + int(DateFromTime(local)), 1.2623 + int(YearFromTime(local))); 1.2624 + break; 1.2625 + case FORMATSPEC_TIME: 1.2626 + /* 09:41:40 GMT-0800 (PST) */ 1.2627 + JS_snprintf(buf, sizeof buf, 1.2628 + "%.2d:%.2d:%.2d GMT%+.4d%s%s", 1.2629 + int(HourFromTime(local)), 1.2630 + int(MinFromTime(local)), 1.2631 + int(SecFromTime(local)), 1.2632 + offset, 1.2633 + usetz ? " " : "", 1.2634 + usetz ? tzbuf : ""); 1.2635 + break; 1.2636 + } 1.2637 + } 1.2638 + 1.2639 + JSString *str = JS_NewStringCopyZ(cx, buf); 1.2640 + if (!str) 1.2641 + return false; 1.2642 + rval.setString(str); 1.2643 + return true; 1.2644 +} 1.2645 + 1.2646 +static bool 1.2647 +ToLocaleFormatHelper(JSContext *cx, HandleObject obj, const char *format, MutableHandleValue rval) 1.2648 +{ 1.2649 + double utctime = obj->as<DateObject>().UTCTime().toNumber(); 1.2650 + 1.2651 + char buf[100]; 1.2652 + if (!IsFinite(utctime)) { 1.2653 + JS_snprintf(buf, sizeof buf, js_NaN_date_str); 1.2654 + } else { 1.2655 + int result_len; 1.2656 + double local = LocalTime(utctime, &cx->runtime()->dateTimeInfo); 1.2657 + PRMJTime split; 1.2658 + new_explode(local, &split, &cx->runtime()->dateTimeInfo); 1.2659 + 1.2660 + /* Let PRMJTime format it. */ 1.2661 + result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split); 1.2662 + 1.2663 + /* If it failed, default to toString. */ 1.2664 + if (result_len == 0) 1.2665 + return date_format(cx, utctime, FORMATSPEC_FULL, rval); 1.2666 + 1.2667 + /* Hacked check against undesired 2-digit year 00/00/00 form. */ 1.2668 + if (strcmp(format, "%x") == 0 && result_len >= 6 && 1.2669 + /* Format %x means use OS settings, which may have 2-digit yr, so 1.2670 + hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/ 1.2671 + !isdigit(buf[result_len - 3]) && 1.2672 + isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) && 1.2673 + /* ...but not if starts with 4-digit year, like 2022/3/11. */ 1.2674 + !(isdigit(buf[0]) && isdigit(buf[1]) && 1.2675 + isdigit(buf[2]) && isdigit(buf[3]))) { 1.2676 + JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2), 1.2677 + "%d", js_DateGetYear(cx, obj)); 1.2678 + } 1.2679 + 1.2680 + } 1.2681 + 1.2682 + if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToUnicode) 1.2683 + return cx->runtime()->localeCallbacks->localeToUnicode(cx, buf, rval); 1.2684 + 1.2685 + JSString *str = JS_NewStringCopyZ(cx, buf); 1.2686 + if (!str) 1.2687 + return false; 1.2688 + rval.setString(str); 1.2689 + return true; 1.2690 +} 1.2691 + 1.2692 +#if !EXPOSE_INTL_API 1.2693 +static bool 1.2694 +ToLocaleStringHelper(JSContext *cx, Handle<DateObject*> dateObj, MutableHandleValue rval) 1.2695 +{ 1.2696 + /* 1.2697 + * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k 1.2698 + * with msvc; '%#c' requests that a full year be used in the result string. 1.2699 + */ 1.2700 + return ToLocaleFormatHelper(cx, dateObj, 1.2701 +#if defined(_WIN32) && !defined(__MWERKS__) 1.2702 + "%#c" 1.2703 +#else 1.2704 + "%c" 1.2705 +#endif 1.2706 + , rval); 1.2707 +} 1.2708 + 1.2709 +/* ES5 15.9.5.5. */ 1.2710 +MOZ_ALWAYS_INLINE bool 1.2711 +date_toLocaleString_impl(JSContext *cx, CallArgs args) 1.2712 +{ 1.2713 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2714 + return ToLocaleStringHelper(cx, dateObj, args.rval()); 1.2715 +} 1.2716 + 1.2717 +static bool 1.2718 +date_toLocaleString(JSContext *cx, unsigned argc, Value *vp) 1.2719 +{ 1.2720 + CallArgs args = CallArgsFromVp(argc, vp); 1.2721 + return CallNonGenericMethod<IsDate, date_toLocaleString_impl>(cx, args); 1.2722 +} 1.2723 + 1.2724 +/* ES5 15.9.5.6. */ 1.2725 +MOZ_ALWAYS_INLINE bool 1.2726 +date_toLocaleDateString_impl(JSContext *cx, CallArgs args) 1.2727 +{ 1.2728 + /* 1.2729 + * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k 1.2730 + * with msvc; '%#x' requests that a full year be used in the result string. 1.2731 + */ 1.2732 + static const char format[] = 1.2733 +#if defined(_WIN32) && !defined(__MWERKS__) 1.2734 + "%#x" 1.2735 +#else 1.2736 + "%x" 1.2737 +#endif 1.2738 + ; 1.2739 + 1.2740 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2741 + return ToLocaleFormatHelper(cx, dateObj, format, args.rval()); 1.2742 +} 1.2743 + 1.2744 +static bool 1.2745 +date_toLocaleDateString(JSContext *cx, unsigned argc, Value *vp) 1.2746 +{ 1.2747 + CallArgs args = CallArgsFromVp(argc, vp); 1.2748 + return CallNonGenericMethod<IsDate, date_toLocaleDateString_impl>(cx, args); 1.2749 +} 1.2750 + 1.2751 +/* ES5 15.9.5.7. */ 1.2752 +MOZ_ALWAYS_INLINE bool 1.2753 +date_toLocaleTimeString_impl(JSContext *cx, CallArgs args) 1.2754 +{ 1.2755 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2756 + return ToLocaleFormatHelper(cx, dateObj, "%X", args.rval()); 1.2757 +} 1.2758 + 1.2759 +static bool 1.2760 +date_toLocaleTimeString(JSContext *cx, unsigned argc, Value *vp) 1.2761 +{ 1.2762 + CallArgs args = CallArgsFromVp(argc, vp); 1.2763 + return CallNonGenericMethod<IsDate, date_toLocaleTimeString_impl>(cx, args); 1.2764 +} 1.2765 +#endif /* !EXPOSE_INTL_API */ 1.2766 + 1.2767 +MOZ_ALWAYS_INLINE bool 1.2768 +date_toLocaleFormat_impl(JSContext *cx, CallArgs args) 1.2769 +{ 1.2770 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2771 + 1.2772 + if (args.length() == 0) { 1.2773 + /* 1.2774 + * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k 1.2775 + * with msvc; '%#c' requests that a full year be used in the result string. 1.2776 + */ 1.2777 + return ToLocaleFormatHelper(cx, dateObj, 1.2778 +#if defined(_WIN32) && !defined(__MWERKS__) 1.2779 + "%#c" 1.2780 +#else 1.2781 + "%c" 1.2782 +#endif 1.2783 + , args.rval()); 1.2784 + } 1.2785 + 1.2786 + RootedString fmt(cx, ToString<CanGC>(cx, args[0])); 1.2787 + if (!fmt) 1.2788 + return false; 1.2789 + 1.2790 + JSAutoByteString fmtbytes(cx, fmt); 1.2791 + if (!fmtbytes) 1.2792 + return false; 1.2793 + 1.2794 + return ToLocaleFormatHelper(cx, dateObj, fmtbytes.ptr(), args.rval()); 1.2795 +} 1.2796 + 1.2797 +static bool 1.2798 +date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp) 1.2799 +{ 1.2800 + CallArgs args = CallArgsFromVp(argc, vp); 1.2801 + return CallNonGenericMethod<IsDate, date_toLocaleFormat_impl>(cx, args); 1.2802 +} 1.2803 + 1.2804 +/* ES5 15.9.5.4. */ 1.2805 +MOZ_ALWAYS_INLINE bool 1.2806 +date_toTimeString_impl(JSContext *cx, CallArgs args) 1.2807 +{ 1.2808 + return date_format(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(), 1.2809 + FORMATSPEC_TIME, args.rval()); 1.2810 +} 1.2811 + 1.2812 +static bool 1.2813 +date_toTimeString(JSContext *cx, unsigned argc, Value *vp) 1.2814 +{ 1.2815 + CallArgs args = CallArgsFromVp(argc, vp); 1.2816 + return CallNonGenericMethod<IsDate, date_toTimeString_impl>(cx, args); 1.2817 +} 1.2818 + 1.2819 +/* ES5 15.9.5.3. */ 1.2820 +MOZ_ALWAYS_INLINE bool 1.2821 +date_toDateString_impl(JSContext *cx, CallArgs args) 1.2822 +{ 1.2823 + return date_format(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(), 1.2824 + FORMATSPEC_DATE, args.rval()); 1.2825 +} 1.2826 + 1.2827 +static bool 1.2828 +date_toDateString(JSContext *cx, unsigned argc, Value *vp) 1.2829 +{ 1.2830 + CallArgs args = CallArgsFromVp(argc, vp); 1.2831 + return CallNonGenericMethod<IsDate, date_toDateString_impl>(cx, args); 1.2832 +} 1.2833 + 1.2834 +#if JS_HAS_TOSOURCE 1.2835 +MOZ_ALWAYS_INLINE bool 1.2836 +date_toSource_impl(JSContext *cx, CallArgs args) 1.2837 +{ 1.2838 + StringBuffer sb(cx); 1.2839 + if (!sb.append("(new Date(") || 1.2840 + !NumberValueToStringBuffer(cx, args.thisv().toObject().as<DateObject>().UTCTime(), sb) || 1.2841 + !sb.append("))")) 1.2842 + { 1.2843 + return false; 1.2844 + } 1.2845 + 1.2846 + JSString *str = sb.finishString(); 1.2847 + if (!str) 1.2848 + return false; 1.2849 + args.rval().setString(str); 1.2850 + return true; 1.2851 +} 1.2852 + 1.2853 +static bool 1.2854 +date_toSource(JSContext *cx, unsigned argc, Value *vp) 1.2855 +{ 1.2856 + CallArgs args = CallArgsFromVp(argc, vp); 1.2857 + return CallNonGenericMethod<IsDate, date_toSource_impl>(cx, args); 1.2858 +} 1.2859 +#endif 1.2860 + 1.2861 +MOZ_ALWAYS_INLINE bool 1.2862 +date_toString_impl(JSContext *cx, CallArgs args) 1.2863 +{ 1.2864 + return date_format(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(), 1.2865 + FORMATSPEC_FULL, args.rval()); 1.2866 +} 1.2867 + 1.2868 +static bool 1.2869 +date_toString(JSContext *cx, unsigned argc, Value *vp) 1.2870 +{ 1.2871 + CallArgs args = CallArgsFromVp(argc, vp); 1.2872 + return CallNonGenericMethod<IsDate, date_toString_impl>(cx, args); 1.2873 +} 1.2874 + 1.2875 +MOZ_ALWAYS_INLINE bool 1.2876 +date_valueOf_impl(JSContext *cx, CallArgs args) 1.2877 +{ 1.2878 + Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); 1.2879 + args.rval().set(dateObj->UTCTime()); 1.2880 + return true; 1.2881 +} 1.2882 + 1.2883 +static bool 1.2884 +date_valueOf(JSContext *cx, unsigned argc, Value *vp) 1.2885 +{ 1.2886 + CallArgs args = CallArgsFromVp(argc, vp); 1.2887 + return CallNonGenericMethod<IsDate, date_valueOf_impl>(cx, args); 1.2888 +} 1.2889 + 1.2890 +static const JSFunctionSpec date_static_methods[] = { 1.2891 + JS_FN("UTC", date_UTC, MAXARGS,0), 1.2892 + JS_FN("parse", date_parse, 1,0), 1.2893 + JS_FN("now", date_now, 0,0), 1.2894 + JS_FS_END 1.2895 +}; 1.2896 + 1.2897 +static const JSFunctionSpec date_methods[] = { 1.2898 + JS_FN("getTime", date_getTime, 0,0), 1.2899 + JS_FN("getTimezoneOffset", date_getTimezoneOffset, 0,0), 1.2900 + JS_FN("getYear", date_getYear, 0,0), 1.2901 + JS_FN("getFullYear", date_getFullYear, 0,0), 1.2902 + JS_FN("getUTCFullYear", date_getUTCFullYear, 0,0), 1.2903 + JS_FN("getMonth", date_getMonth, 0,0), 1.2904 + JS_FN("getUTCMonth", date_getUTCMonth, 0,0), 1.2905 + JS_FN("getDate", date_getDate, 0,0), 1.2906 + JS_FN("getUTCDate", date_getUTCDate, 0,0), 1.2907 + JS_FN("getDay", date_getDay, 0,0), 1.2908 + JS_FN("getUTCDay", date_getUTCDay, 0,0), 1.2909 + JS_FN("getHours", date_getHours, 0,0), 1.2910 + JS_FN("getUTCHours", date_getUTCHours, 0,0), 1.2911 + JS_FN("getMinutes", date_getMinutes, 0,0), 1.2912 + JS_FN("getUTCMinutes", date_getUTCMinutes, 0,0), 1.2913 + JS_FN("getSeconds", date_getUTCSeconds, 0,0), 1.2914 + JS_FN("getUTCSeconds", date_getUTCSeconds, 0,0), 1.2915 + JS_FN("getMilliseconds", date_getUTCMilliseconds, 0,0), 1.2916 + JS_FN("getUTCMilliseconds", date_getUTCMilliseconds, 0,0), 1.2917 + JS_FN("setTime", date_setTime, 1,0), 1.2918 + JS_FN("setYear", date_setYear, 1,0), 1.2919 + JS_FN("setFullYear", date_setFullYear, 3,0), 1.2920 + JS_FN("setUTCFullYear", date_setUTCFullYear, 3,0), 1.2921 + JS_FN("setMonth", date_setMonth, 2,0), 1.2922 + JS_FN("setUTCMonth", date_setUTCMonth, 2,0), 1.2923 + JS_FN("setDate", date_setDate, 1,0), 1.2924 + JS_FN("setUTCDate", date_setUTCDate, 1,0), 1.2925 + JS_FN("setHours", date_setHours, 4,0), 1.2926 + JS_FN("setUTCHours", date_setUTCHours, 4,0), 1.2927 + JS_FN("setMinutes", date_setMinutes, 3,0), 1.2928 + JS_FN("setUTCMinutes", date_setUTCMinutes, 3,0), 1.2929 + JS_FN("setSeconds", date_setSeconds, 2,0), 1.2930 + JS_FN("setUTCSeconds", date_setUTCSeconds, 2,0), 1.2931 + JS_FN("setMilliseconds", date_setMilliseconds, 1,0), 1.2932 + JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0), 1.2933 + JS_FN("toUTCString", date_toGMTString, 0,0), 1.2934 + JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0), 1.2935 +#if EXPOSE_INTL_API 1.2936 + JS_SELF_HOSTED_FN(js_toLocaleString_str, "Date_toLocaleString", 0,0), 1.2937 + JS_SELF_HOSTED_FN("toLocaleDateString", "Date_toLocaleDateString", 0,0), 1.2938 + JS_SELF_HOSTED_FN("toLocaleTimeString", "Date_toLocaleTimeString", 0,0), 1.2939 +#else 1.2940 + JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0), 1.2941 + JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0), 1.2942 + JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0), 1.2943 +#endif 1.2944 + JS_FN("toDateString", date_toDateString, 0,0), 1.2945 + JS_FN("toTimeString", date_toTimeString, 0,0), 1.2946 + JS_FN("toISOString", date_toISOString, 0,0), 1.2947 + JS_FN(js_toJSON_str, date_toJSON, 1,0), 1.2948 +#if JS_HAS_TOSOURCE 1.2949 + JS_FN(js_toSource_str, date_toSource, 0,0), 1.2950 +#endif 1.2951 + JS_FN(js_toString_str, date_toString, 0,0), 1.2952 + JS_FN(js_valueOf_str, date_valueOf, 0,0), 1.2953 + JS_FS_END 1.2954 +}; 1.2955 + 1.2956 +bool 1.2957 +js_Date(JSContext *cx, unsigned argc, Value *vp) 1.2958 +{ 1.2959 + CallArgs args = CallArgsFromVp(argc, vp); 1.2960 + 1.2961 + /* Date called as function. */ 1.2962 + if (!args.isConstructing()) 1.2963 + return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, args.rval()); 1.2964 + 1.2965 + /* Date called as constructor. */ 1.2966 + double d; 1.2967 + if (args.length() == 0) { 1.2968 + /* ES5 15.9.3.3. */ 1.2969 + d = NowAsMillis(); 1.2970 + } else if (args.length() == 1) { 1.2971 + /* ES5 15.9.3.2. */ 1.2972 + 1.2973 + /* Step 1. */ 1.2974 + if (!ToPrimitive(cx, args[0])) 1.2975 + return false; 1.2976 + 1.2977 + if (args[0].isString()) { 1.2978 + /* Step 2. */ 1.2979 + JSString *str = args[0].toString(); 1.2980 + if (!str) 1.2981 + return false; 1.2982 + 1.2983 + JSLinearString *linearStr = str->ensureLinear(cx); 1.2984 + if (!linearStr) 1.2985 + return false; 1.2986 + 1.2987 + if (!date_parseString(linearStr, &d, &cx->runtime()->dateTimeInfo)) 1.2988 + d = GenericNaN(); 1.2989 + else 1.2990 + d = TimeClip(d); 1.2991 + } else { 1.2992 + /* Step 3. */ 1.2993 + if (!ToNumber(cx, args[0], &d)) 1.2994 + return false; 1.2995 + d = TimeClip(d); 1.2996 + } 1.2997 + } else { 1.2998 + double msec_time; 1.2999 + if (!date_msecFromArgs(cx, args, &msec_time)) 1.3000 + return false; 1.3001 + 1.3002 + if (IsFinite(msec_time)) { 1.3003 + msec_time = UTC(msec_time, &cx->runtime()->dateTimeInfo); 1.3004 + msec_time = TimeClip(msec_time); 1.3005 + } 1.3006 + d = msec_time; 1.3007 + } 1.3008 + 1.3009 + JSObject *obj = js_NewDateObjectMsec(cx, d); 1.3010 + if (!obj) 1.3011 + return false; 1.3012 + 1.3013 + args.rval().setObject(*obj); 1.3014 + return true; 1.3015 +} 1.3016 + 1.3017 +static bool 1.3018 +FinishDateClassInit(JSContext *cx, HandleObject ctor, HandleObject proto) 1.3019 +{ 1.3020 + proto->as<DateObject>().setUTCTime(GenericNaN()); 1.3021 + 1.3022 + /* 1.3023 + * Date.prototype.toGMTString has the same initial value as 1.3024 + * Date.prototype.toUTCString. 1.3025 + */ 1.3026 + RootedValue toUTCStringFun(cx); 1.3027 + RootedId toUTCStringId(cx, NameToId(cx->names().toUTCString)); 1.3028 + RootedId toGMTStringId(cx, NameToId(cx->names().toGMTString)); 1.3029 + return baseops::GetProperty(cx, proto, toUTCStringId, &toUTCStringFun) && 1.3030 + baseops::DefineGeneric(cx, proto, toGMTStringId, toUTCStringFun, 1.3031 + JS_PropertyStub, JS_StrictPropertyStub, 0); 1.3032 +} 1.3033 + 1.3034 +const Class DateObject::class_ = { 1.3035 + js_Date_str, 1.3036 + JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | 1.3037 + JSCLASS_HAS_CACHED_PROTO(JSProto_Date), 1.3038 + JS_PropertyStub, /* addProperty */ 1.3039 + JS_DeletePropertyStub, /* delProperty */ 1.3040 + JS_PropertyStub, /* getProperty */ 1.3041 + JS_StrictPropertyStub, /* setProperty */ 1.3042 + JS_EnumerateStub, 1.3043 + JS_ResolveStub, 1.3044 + date_convert, 1.3045 + nullptr, /* finalize */ 1.3046 + nullptr, /* call */ 1.3047 + nullptr, /* hasInstance */ 1.3048 + nullptr, /* construct */ 1.3049 + nullptr, /* trace */ 1.3050 + { 1.3051 + GenericCreateConstructor<js_Date, NAME_OFFSET(Date), MAXARGS>, 1.3052 + GenericCreatePrototype<&DateObject::class_>, 1.3053 + date_static_methods, 1.3054 + date_methods, 1.3055 + FinishDateClassInit 1.3056 + } 1.3057 +}; 1.3058 + 1.3059 +JS_FRIEND_API(JSObject *) 1.3060 +js_NewDateObjectMsec(JSContext *cx, double msec_time) 1.3061 +{ 1.3062 + JSObject *obj = NewBuiltinClassInstance(cx, &DateObject::class_); 1.3063 + if (!obj) 1.3064 + return nullptr; 1.3065 + obj->as<DateObject>().setUTCTime(msec_time); 1.3066 + return obj; 1.3067 +} 1.3068 + 1.3069 +JS_FRIEND_API(JSObject *) 1.3070 +js_NewDateObject(JSContext *cx, int year, int mon, int mday, 1.3071 + int hour, int min, int sec) 1.3072 +{ 1.3073 + JS_ASSERT(mon < 12); 1.3074 + double msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); 1.3075 + return js_NewDateObjectMsec(cx, UTC(msec_time, &cx->runtime()->dateTimeInfo)); 1.3076 +} 1.3077 + 1.3078 +JS_FRIEND_API(bool) 1.3079 +js_DateIsValid(JSObject *obj) 1.3080 +{ 1.3081 + return obj->is<DateObject>() && !IsNaN(obj->as<DateObject>().UTCTime().toNumber()); 1.3082 +} 1.3083 + 1.3084 +JS_FRIEND_API(int) 1.3085 +js_DateGetYear(JSContext *cx, JSObject *obj) 1.3086 +{ 1.3087 + /* Preserve legacy API behavior of returning 0 for invalid dates. */ 1.3088 + JS_ASSERT(obj); 1.3089 + double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo); 1.3090 + if (IsNaN(localtime)) 1.3091 + return 0; 1.3092 + 1.3093 + return (int) YearFromTime(localtime); 1.3094 +} 1.3095 + 1.3096 +JS_FRIEND_API(int) 1.3097 +js_DateGetMonth(JSContext *cx, JSObject *obj) 1.3098 +{ 1.3099 + JS_ASSERT(obj); 1.3100 + double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo); 1.3101 + if (IsNaN(localtime)) 1.3102 + return 0; 1.3103 + 1.3104 + return (int) MonthFromTime(localtime); 1.3105 +} 1.3106 + 1.3107 +JS_FRIEND_API(int) 1.3108 +js_DateGetDate(JSContext *cx, JSObject *obj) 1.3109 +{ 1.3110 + JS_ASSERT(obj); 1.3111 + double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo); 1.3112 + if (IsNaN(localtime)) 1.3113 + return 0; 1.3114 + 1.3115 + return (int) DateFromTime(localtime); 1.3116 +} 1.3117 + 1.3118 +JS_FRIEND_API(int) 1.3119 +js_DateGetHours(JSContext *cx, JSObject *obj) 1.3120 +{ 1.3121 + JS_ASSERT(obj); 1.3122 + double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo); 1.3123 + if (IsNaN(localtime)) 1.3124 + return 0; 1.3125 + 1.3126 + return (int) HourFromTime(localtime); 1.3127 +} 1.3128 + 1.3129 +JS_FRIEND_API(int) 1.3130 +js_DateGetMinutes(JSContext *cx, JSObject *obj) 1.3131 +{ 1.3132 + JS_ASSERT(obj); 1.3133 + double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo); 1.3134 + if (IsNaN(localtime)) 1.3135 + return 0; 1.3136 + 1.3137 + return (int) MinFromTime(localtime); 1.3138 +} 1.3139 + 1.3140 +JS_FRIEND_API(int) 1.3141 +js_DateGetSeconds(JSObject *obj) 1.3142 +{ 1.3143 + if (!obj->is<DateObject>()) 1.3144 + return 0; 1.3145 + 1.3146 + double utctime = obj->as<DateObject>().UTCTime().toNumber(); 1.3147 + if (IsNaN(utctime)) 1.3148 + return 0; 1.3149 + return (int) SecFromTime(utctime); 1.3150 +} 1.3151 + 1.3152 +JS_FRIEND_API(double) 1.3153 +js_DateGetMsecSinceEpoch(JSObject *obj) 1.3154 +{ 1.3155 + return obj->is<DateObject>() ? obj->as<DateObject>().UTCTime().toNumber() : 0; 1.3156 +} 1.3157 + 1.3158 + 1.3159 +static const NativeImpl sReadOnlyDateMethods[] = { 1.3160 + DateObject::getTime_impl, 1.3161 + DateObject::getYear_impl, 1.3162 + DateObject::getFullYear_impl, 1.3163 + DateObject::getUTCFullYear_impl, 1.3164 + DateObject::getMonth_impl, 1.3165 + DateObject::getUTCMonth_impl, 1.3166 + DateObject::getDate_impl, 1.3167 + DateObject::getUTCDate_impl, 1.3168 + DateObject::getDay_impl, 1.3169 + DateObject::getUTCDay_impl, 1.3170 + DateObject::getHours_impl, 1.3171 + DateObject::getUTCHours_impl, 1.3172 + DateObject::getMinutes_impl, 1.3173 + DateObject::getUTCMinutes_impl, 1.3174 + DateObject::getUTCSeconds_impl, 1.3175 + DateObject::getUTCMilliseconds_impl, 1.3176 + DateObject::getTimezoneOffset_impl, 1.3177 + date_toGMTString_impl, 1.3178 + date_toISOString_impl, 1.3179 + date_toLocaleFormat_impl, 1.3180 + date_toTimeString_impl, 1.3181 + date_toDateString_impl, 1.3182 + date_toSource_impl, 1.3183 + date_toString_impl, 1.3184 + date_valueOf_impl 1.3185 +};