1 |
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
|
* |
3 |
|
* ***** BEGIN LICENSE BLOCK ***** |
4 |
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
5 |
|
* |
6 |
|
* The contents of this file are subject to the Mozilla Public License Version |
7 |
|
* 1.1 (the "License"); you may not use this file except in compliance with |
8 |
|
* the License. You may obtain a copy of the License at |
9 |
|
* http://www.mozilla.org/MPL/ |
10 |
|
* |
11 |
|
* Software distributed under the License is distributed on an "AS IS" basis, |
12 |
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 |
|
* for the specific language governing rights and limitations under the |
14 |
|
* License. |
15 |
|
* |
16 |
|
* The Original Code is Mozilla Communicator client code, released |
17 |
|
* March 31, 1998. |
18 |
|
* |
19 |
|
* The Initial Developer of the Original Code is |
20 |
|
* Netscape Communications Corporation. |
21 |
|
* Portions created by the Initial Developer are Copyright (C) 1998 |
22 |
|
* the Initial Developer. All Rights Reserved. |
23 |
|
* |
24 |
|
* Contributor(s): |
25 |
|
* |
26 |
|
* Alternatively, the contents of this file may be used under the terms of |
27 |
|
* either of the GNU General Public License Version 2 or later (the "GPL"), |
28 |
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
29 |
|
* in which case the provisions of the GPL or the LGPL are applicable instead |
30 |
|
* of those above. If you wish to allow use of your version of this file only |
31 |
|
* under the terms of either the GPL or the LGPL, and not to allow others to |
32 |
|
* use your version of this file under the terms of the MPL, indicate your |
33 |
|
* decision by deleting the provisions above and replace them with the notice |
34 |
|
* and other provisions required by the GPL or the LGPL. If you do not delete |
35 |
|
* the provisions above, a recipient may use your version of this file under |
36 |
|
* the terms of any one of the MPL, the GPL or the LGPL. |
37 |
|
* |
38 |
|
* ***** END LICENSE BLOCK ***** */ |
39 |
|
|
40 |
|
/* |
41 |
|
* JS date methods. |
42 |
|
*/ |
43 |
|
|
44 |
|
/* |
45 |
|
* "For example, OS/360 devotes 26 bytes of the permanently |
46 |
|
* resident date-turnover routine to the proper handling of |
47 |
|
* December 31 on leap years (when it is Day 366). That |
48 |
|
* might have been left to the operator." |
49 |
|
* |
50 |
|
* Frederick Brooks, 'The Second-System Effect'. |
51 |
|
*/ |
52 |
|
|
53 |
|
#include "jsstddef.h" |
54 |
|
#include <ctype.h> |
55 |
|
#include <locale.h> |
56 |
|
#include <math.h> |
57 |
|
#include <stdlib.h> |
58 |
|
#include <string.h> |
59 |
|
#include "jstypes.h" |
60 |
|
#include "jsprf.h" |
61 |
|
#include "prmjtime.h" |
62 |
|
#include "jsutil.h" /* Added by JSIFY */ |
63 |
|
#include "jsapi.h" |
64 |
|
#include "jsconfig.h" |
65 |
|
#include "jscntxt.h" |
66 |
|
#include "jsdate.h" |
67 |
|
#include "jsinterp.h" |
68 |
|
#include "jsnum.h" |
69 |
|
#include "jsobj.h" |
70 |
|
#include "jsstr.h" |
71 |
|
|
72 |
|
/* |
73 |
|
* The JS 'Date' object is patterned after the Java 'Date' object. |
74 |
|
* Here is an script: |
75 |
|
* |
76 |
|
* today = new Date(); |
77 |
|
* |
78 |
|
* print(today.toLocaleString()); |
79 |
|
* |
80 |
|
* weekDay = today.getDay(); |
81 |
|
* |
82 |
|
* |
83 |
|
* These Java (and ECMA-262) methods are supported: |
84 |
|
* |
85 |
|
* UTC |
86 |
|
* getDate (getUTCDate) |
87 |
|
* getDay (getUTCDay) |
88 |
|
* getHours (getUTCHours) |
89 |
|
* getMinutes (getUTCMinutes) |
90 |
|
* getMonth (getUTCMonth) |
91 |
|
* getSeconds (getUTCSeconds) |
92 |
|
* getMilliseconds (getUTCMilliseconds) |
93 |
|
* getTime |
94 |
|
* getTimezoneOffset |
95 |
|
* getYear |
96 |
|
* getFullYear (getUTCFullYear) |
97 |
|
* parse |
98 |
|
* setDate (setUTCDate) |
99 |
|
* setHours (setUTCHours) |
100 |
|
* setMinutes (setUTCMinutes) |
101 |
|
* setMonth (setUTCMonth) |
102 |
|
* setSeconds (setUTCSeconds) |
103 |
|
* setMilliseconds (setUTCMilliseconds) |
104 |
|
* setTime |
105 |
|
* setYear (setFullYear, setUTCFullYear) |
106 |
|
* toGMTString (toUTCString) |
107 |
|
* toLocaleString |
108 |
|
* toString |
109 |
|
* |
110 |
|
* |
111 |
|
* These Java methods are not supported |
112 |
|
* |
113 |
|
* setDay |
114 |
|
* before |
115 |
|
* after |
116 |
|
* equals |
117 |
|
* hashCode |
118 |
|
*/ |
119 |
|
|
120 |
|
/* |
121 |
|
* 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language |
122 |
|
* definition and reduce dependence on NSPR. NSPR is used to get the current |
123 |
|
* time in milliseconds, the time zone offset, and the daylight savings time |
124 |
|
* offset for a given time. NSPR is also used for Date.toLocaleString(), for |
125 |
|
* locale-specific formatting, and to get a string representing the timezone. |
126 |
|
* (Which turns out to be platform-dependent.) |
127 |
|
* |
128 |
|
* To do: |
129 |
|
* (I did some performance tests by timing how long it took to run what |
130 |
|
* I had of the js ECMA conformance tests.) |
131 |
|
* |
132 |
|
* - look at saving results across multiple calls to supporting |
133 |
|
* functions; the toString functions compute some of the same values |
134 |
|
* multiple times. Although - I took a quick stab at this, and I lost |
135 |
|
* rather than gained. (Fractionally.) Hard to tell what compilers/processors |
136 |
|
* are doing these days. |
137 |
|
* |
138 |
|
* - look at tweaking function return types to return double instead |
139 |
|
* of int; this seems to make things run slightly faster sometimes. |
140 |
|
* (though it could be architecture-dependent.) It'd be good to see |
141 |
|
* how this does on win32. (Tried it on irix.) Types could use a |
142 |
|
* general going-over. |
143 |
|
*/ |
144 |
|
|
145 |
|
/* |
146 |
|
* Supporting functions - ECMA 15.9.1.* |
147 |
|
*/ |
148 |
|
|
149 |
|
#define HalfTimeDomain 8.64e15 |
150 |
|
#define HoursPerDay 24.0 |
151 |
|
#define MinutesPerDay (HoursPerDay * MinutesPerHour) |
152 |
|
#define MinutesPerHour 60.0 |
153 |
|
#define SecondsPerDay (MinutesPerDay * SecondsPerMinute) |
154 |
|
#define SecondsPerHour (MinutesPerHour * SecondsPerMinute) |
155 |
|
#define SecondsPerMinute 60.0 |
156 |
|
|
157 |
|
#if defined(XP_WIN) || defined(XP_OS2) |
158 |
|
/* Work around msvc double optimization bug by making these runtime values; if |
159 |
|
* they're available at compile time, msvc optimizes division by them by |
160 |
|
* computing the reciprocal and multiplying instead of dividing - this loses |
161 |
|
* when the reciprocal isn't representable in a double. |
162 |
|
*/ |
163 |
|
static jsdouble msPerSecond = 1000.0; |
164 |
|
static jsdouble msPerDay = SecondsPerDay * 1000.0; |
165 |
|
static jsdouble msPerHour = SecondsPerHour * 1000.0; |
166 |
|
static jsdouble msPerMinute = SecondsPerMinute * 1000.0; |
167 |
|
#else |
168 |
|
#define msPerDay (SecondsPerDay * msPerSecond) |
169 |
|
#define msPerHour (SecondsPerHour * msPerSecond) |
170 |
|
#define msPerMinute (SecondsPerMinute * msPerSecond) |
171 |
|
#define msPerSecond 1000.0 |
172 |
|
#endif |
173 |
|
|
174 |
|
#define Day(t) floor((t) / msPerDay) |
175 |
|
|
176 |
|
static jsdouble |
177 |
|
TimeWithinDay(jsdouble t) |
178 |
0 |
{ |
179 |
0 |
jsdouble result; |
180 |
0 |
result = fmod(t, msPerDay); |
181 |
0 |
if (result < 0) |
182 |
0 |
result += msPerDay; |
183 |
0 |
return result; |
184 |
|
} |
185 |
|
|
186 |
|
#define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \ |
187 |
|
? 366 : 365) |
188 |
|
|
189 |
|
/* math here has to be f.p, because we need |
190 |
|
* floor((1968 - 1969) / 4) == -1 |
191 |
|
*/ |
192 |
|
#define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \ |
193 |
|
- floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0)) |
194 |
|
#define TimeFromYear(y) (DayFromYear(y) * msPerDay) |
195 |
|
|
196 |
|
static jsint |
197 |
|
YearFromTime(jsdouble t) |
198 |
0 |
{ |
199 |
0 |
jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970; |
200 |
0 |
jsdouble t2 = (jsdouble) TimeFromYear(y); |
201 |
|
|
202 |
0 |
if (t2 > t) { |
203 |
0 |
y--; |
204 |
|
} else { |
205 |
0 |
if (t2 + msPerDay * DaysInYear(y) <= t) |
206 |
0 |
y++; |
207 |
|
} |
208 |
0 |
return y; |
209 |
|
} |
210 |
|
|
211 |
|
#define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366) |
212 |
|
|
213 |
|
#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year))) |
214 |
|
|
215 |
|
/* |
216 |
|
* The following array contains the day of year for the first day of |
217 |
|
* each month, where index 0 is January, and day 0 is January 1. |
218 |
|
*/ |
219 |
|
static jsdouble firstDayOfMonth[2][12] = { |
220 |
|
{0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0}, |
221 |
|
{0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0} |
222 |
|
}; |
223 |
|
|
224 |
|
#define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m]; |
225 |
|
|
226 |
|
static intN |
227 |
|
MonthFromTime(jsdouble t) |
228 |
0 |
{ |
229 |
0 |
intN d, step; |
230 |
0 |
jsint year = YearFromTime(t); |
231 |
0 |
d = DayWithinYear(t, year); |
232 |
|
|
233 |
0 |
if (d < (step = 31)) |
234 |
0 |
return 0; |
235 |
0 |
step += (InLeapYear(t) ? 29 : 28); |
236 |
0 |
if (d < step) |
237 |
0 |
return 1; |
238 |
0 |
if (d < (step += 31)) |
239 |
0 |
return 2; |
240 |
0 |
if (d < (step += 30)) |
241 |
0 |
return 3; |
242 |
0 |
if (d < (step += 31)) |
243 |
0 |
return 4; |
244 |
0 |
if (d < (step += 30)) |
245 |
0 |
return 5; |
246 |
0 |
if (d < (step += 31)) |
247 |
0 |
return 6; |
248 |
0 |
if (d < (step += 31)) |
249 |
0 |
return 7; |
250 |
0 |
if (d < (step += 30)) |
251 |
0 |
return 8; |
252 |
0 |
if (d < (step += 31)) |
253 |
0 |
return 9; |
254 |
0 |
if (d < (step += 30)) |
255 |
0 |
return 10; |
256 |
0 |
return 11; |
257 |
|
} |
258 |
|
|
259 |
|
static intN |
260 |
|
DateFromTime(jsdouble t) |
261 |
0 |
{ |
262 |
0 |
intN d, step, next; |
263 |
0 |
jsint year = YearFromTime(t); |
264 |
0 |
d = DayWithinYear(t, year); |
265 |
|
|
266 |
0 |
if (d <= (next = 30)) |
267 |
0 |
return d + 1; |
268 |
0 |
step = next; |
269 |
0 |
next += (InLeapYear(t) ? 29 : 28); |
270 |
0 |
if (d <= next) |
271 |
0 |
return d - step; |
272 |
0 |
step = next; |
273 |
0 |
if (d <= (next += 31)) |
274 |
0 |
return d - step; |
275 |
0 |
step = next; |
276 |
0 |
if (d <= (next += 30)) |
277 |
0 |
return d - step; |
278 |
0 |
step = next; |
279 |
0 |
if (d <= (next += 31)) |
280 |
0 |
return d - step; |
281 |
0 |
step = next; |
282 |
0 |
if (d <= (next += 30)) |
283 |
0 |
return d - step; |
284 |
0 |
step = next; |
285 |
0 |
if (d <= (next += 31)) |
286 |
0 |
return d - step; |
287 |
0 |
step = next; |
288 |
0 |
if (d <= (next += 31)) |
289 |
0 |
return d - step; |
290 |
0 |
step = next; |
291 |
0 |
if (d <= (next += 30)) |
292 |
0 |
return d - step; |
293 |
0 |
step = next; |
294 |
0 |
if (d <= (next += 31)) |
295 |
0 |
return d - step; |
296 |
0 |
step = next; |
297 |
0 |
if (d <= (next += 30)) |
298 |
0 |
return d - step; |
299 |
0 |
step = next; |
300 |
0 |
return d - step; |
301 |
|
} |
302 |
|
|
303 |
|
static intN |
304 |
|
WeekDay(jsdouble t) |
305 |
0 |
{ |
306 |
0 |
jsint result; |
307 |
0 |
result = (jsint) Day(t) + 4; |
308 |
0 |
result = result % 7; |
309 |
0 |
if (result < 0) |
310 |
0 |
result += 7; |
311 |
0 |
return (intN) result; |
312 |
|
} |
313 |
|
|
314 |
|
#define MakeTime(hour, min, sec, ms) \ |
315 |
|
((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms)) |
316 |
|
|
317 |
|
static jsdouble |
318 |
|
MakeDay(jsdouble year, jsdouble month, jsdouble date) |
319 |
0 |
{ |
320 |
0 |
JSBool leap; |
321 |
0 |
jsdouble yearday; |
322 |
0 |
jsdouble monthday; |
323 |
|
|
324 |
0 |
year += floor(month / 12); |
325 |
|
|
326 |
0 |
month = fmod(month, 12.0); |
327 |
0 |
if (month < 0) |
328 |
0 |
month += 12; |
329 |
|
|
330 |
0 |
leap = (DaysInYear((jsint) year) == 366); |
331 |
|
|
332 |
0 |
yearday = floor(TimeFromYear(year) / msPerDay); |
333 |
0 |
monthday = DayFromMonth(month, leap); |
334 |
|
|
335 |
0 |
return yearday + monthday + date - 1; |
336 |
|
} |
337 |
|
|
338 |
|
#define MakeDate(day, time) ((day) * msPerDay + (time)) |
339 |
|
|
340 |
|
/* |
341 |
|
* Years and leap years on which Jan 1 is a Sunday, Monday, etc. |
342 |
|
* |
343 |
|
* yearStartingWith[0][i] is an example non-leap year where |
344 |
|
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. |
345 |
|
* |
346 |
|
* yearStartingWith[1][i] is an example leap year where |
347 |
|
* Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. |
348 |
|
*/ |
349 |
|
static jsint yearStartingWith[2][7] = { |
350 |
|
{1978, 1973, 1974, 1975, 1981, 1971, 1977}, |
351 |
|
{1984, 1996, 1980, 1992, 1976, 1988, 1972} |
352 |
|
}; |
353 |
|
|
354 |
|
/* |
355 |
|
* Find a year for which any given date will fall on the same weekday. |
356 |
|
* |
357 |
|
* This function should be used with caution when used other than |
358 |
|
* for determining DST; it hasn't been proven not to produce an |
359 |
|
* incorrect year for times near year boundaries. |
360 |
|
*/ |
361 |
|
static jsint |
362 |
0 |
EquivalentYearForDST(jsint year) { |
363 |
0 |
jsint day; |
364 |
0 |
JSBool isLeapYear; |
365 |
|
|
366 |
0 |
day = (jsint) DayFromYear(year) + 4; |
367 |
0 |
day = day % 7; |
368 |
0 |
if (day < 0) |
369 |
0 |
day += 7; |
370 |
|
|
371 |
0 |
isLeapYear = (DaysInYear(year) == 366); |
372 |
|
|
373 |
0 |
return yearStartingWith[isLeapYear][day]; |
374 |
|
} |
375 |
|
|
376 |
|
/* LocalTZA gets set by js_InitDateClass() */ |
377 |
|
static jsdouble LocalTZA; |
378 |
|
|
379 |
|
static jsdouble |
380 |
|
DaylightSavingTA(jsdouble t) |
381 |
0 |
{ |
382 |
0 |
volatile int64 PR_t; |
383 |
0 |
int64 ms2us; |
384 |
0 |
int64 offset; |
385 |
0 |
jsdouble result; |
386 |
|
|
387 |
|
/* abort if NaN */ |
388 |
0 |
if (JSDOUBLE_IS_NaN(t)) |
389 |
0 |
return t; |
390 |
|
|
391 |
|
/* |
392 |
|
* If earlier than 1970 or after 2038, potentially beyond the ken of |
393 |
|
* many OSes, map it to an equivalent year before asking. |
394 |
|
*/ |
395 |
0 |
if (t < 0.0 || t > 2145916800000.0) { |
396 |
0 |
jsint year; |
397 |
0 |
jsdouble day; |
398 |
|
|
399 |
0 |
year = EquivalentYearForDST(YearFromTime(t)); |
400 |
0 |
day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); |
401 |
0 |
t = MakeDate(day, TimeWithinDay(t)); |
402 |
|
} |
403 |
|
|
404 |
|
/* put our t in an LL, and map it to usec for prtime */ |
405 |
0 |
JSLL_D2L(PR_t, t); |
406 |
0 |
JSLL_I2L(ms2us, PRMJ_USEC_PER_MSEC); |
407 |
0 |
JSLL_MUL(PR_t, PR_t, ms2us); |
408 |
|
|
409 |
0 |
offset = PRMJ_DSTOffset(PR_t); |
410 |
|
|
411 |
0 |
JSLL_DIV(offset, offset, ms2us); |
412 |
0 |
JSLL_L2D(result, offset); |
413 |
0 |
return result; |
414 |
|
} |
415 |
|
|
416 |
|
|
417 |
|
#define AdjustTime(t) fmod(LocalTZA + DaylightSavingTA(t), msPerDay) |
418 |
|
|
419 |
|
#define LocalTime(t) ((t) + AdjustTime(t)) |
420 |
|
|
421 |
|
static jsdouble |
422 |
|
UTC(jsdouble t) |
423 |
0 |
{ |
424 |
0 |
return t - AdjustTime(t - LocalTZA); |
425 |
|
} |
426 |
|
|
427 |
|
static intN |
428 |
|
HourFromTime(jsdouble t) |
429 |
0 |
{ |
430 |
0 |
intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay); |
431 |
0 |
if (result < 0) |
432 |
0 |
result += (intN)HoursPerDay; |
433 |
0 |
return result; |
434 |
|
} |
435 |
|
|
436 |
|
static intN |
437 |
|
MinFromTime(jsdouble t) |
438 |
0 |
{ |
439 |
0 |
intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour); |
440 |
0 |
if (result < 0) |
441 |
0 |
result += (intN)MinutesPerHour; |
442 |
0 |
return result; |
443 |
|
} |
444 |
|
|
445 |
|
static intN |
446 |
|
SecFromTime(jsdouble t) |
447 |
0 |
{ |
448 |
0 |
intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute); |
449 |
0 |
if (result < 0) |
450 |
0 |
result += (intN)SecondsPerMinute; |
451 |
0 |
return result; |
452 |
|
} |
453 |
|
|
454 |
|
static intN |
455 |
|
msFromTime(jsdouble t) |
456 |
0 |
{ |
457 |
0 |
intN result = (intN) fmod(t, msPerSecond); |
458 |
0 |
if (result < 0) |
459 |
0 |
result += (intN)msPerSecond; |
460 |
0 |
return result; |
461 |
|
} |
462 |
|
|
463 |
|
#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \ |
464 |
|
&& !((d < 0 ? -d : d) > HalfTimeDomain)) \ |
465 |
|
? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN) |
466 |
|
|
467 |
|
/** |
468 |
|
* end of ECMA 'support' functions |
469 |
|
*/ |
470 |
|
|
471 |
|
/* |
472 |
|
* Other Support routines and definitions |
473 |
|
*/ |
474 |
|
|
475 |
|
static JSClass date_class = { |
476 |
|
js_Date_str, |
477 |
|
JSCLASS_HAS_PRIVATE, |
478 |
|
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, |
479 |
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, |
480 |
|
JSCLASS_NO_OPTIONAL_MEMBERS |
481 |
|
}; |
482 |
|
|
483 |
|
/* for use by date_parse */ |
484 |
|
|
485 |
|
static const char* wtb[] = { |
486 |
|
"am", "pm", |
487 |
|
"monday", "tuesday", "wednesday", "thursday", "friday", |
488 |
|
"saturday", "sunday", |
489 |
|
"january", "february", "march", "april", "may", "june", |
490 |
|
"july", "august", "september", "october", "november", "december", |
491 |
|
"gmt", "ut", "utc", |
492 |
|
"est", "edt", |
493 |
|
"cst", "cdt", |
494 |
|
"mst", "mdt", |
495 |
|
"pst", "pdt" |
496 |
|
/* time zone table needs to be expanded */ |
497 |
|
}; |
498 |
|
|
499 |
|
static int ttb[] = { |
500 |
|
-1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */ |
501 |
|
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, |
502 |
|
10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */ |
503 |
|
10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */ |
504 |
|
10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */ |
505 |
|
10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */ |
506 |
|
10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */ |
507 |
|
}; |
508 |
|
|
509 |
|
/* helper for date_parse */ |
510 |
|
static JSBool |
511 |
|
date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off, |
512 |
|
int count, int ignoreCase) |
513 |
0 |
{ |
514 |
0 |
JSBool result = JS_FALSE; |
515 |
|
/* return true if matches, otherwise, false */ |
516 |
|
|
517 |
0 |
while (count > 0 && s1[s1off] && s2[s2off]) { |
518 |
0 |
if (ignoreCase) { |
519 |
0 |
if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) { |
520 |
0 |
break; |
521 |
|
} |
522 |
|
} else { |
523 |
0 |
if ((jschar)s1[s1off] != s2[s2off]) { |
524 |
0 |
break; |
525 |
|
} |
526 |
|
} |
527 |
0 |
s1off++; |
528 |
0 |
s2off++; |
529 |
0 |
count--; |
530 |
|
} |
531 |
|
|
532 |
0 |
if (count == 0) { |
533 |
0 |
result = JS_TRUE; |
534 |
|
} |
535 |
|
|
536 |
0 |
return result; |
537 |
|
} |
538 |
|
|
539 |
|
/* find UTC time from given date... no 1900 correction! */ |
540 |
|
static jsdouble |
541 |
|
date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour, |
542 |
|
jsdouble min, jsdouble sec, jsdouble msec) |
543 |
0 |
{ |
544 |
0 |
jsdouble day; |
545 |
0 |
jsdouble msec_time; |
546 |
0 |
jsdouble result; |
547 |
|
|
548 |
0 |
day = MakeDay(year, mon, mday); |
549 |
0 |
msec_time = MakeTime(hour, min, sec, msec); |
550 |
0 |
result = MakeDate(day, msec_time); |
551 |
0 |
return result; |
552 |
|
} |
553 |
|
|
554 |
|
/* |
555 |
|
* See ECMA 15.9.4.[3-10]; |
556 |
|
*/ |
557 |
|
/* XXX this function must be above date_parseString to avoid a |
558 |
|
horrid bug in the Win16 1.52 compiler */ |
559 |
|
#define MAXARGS 7 |
560 |
|
static JSBool |
561 |
|
date_UTC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
562 |
0 |
{ |
563 |
0 |
jsdouble array[MAXARGS]; |
564 |
0 |
uintN loop; |
565 |
0 |
jsdouble d; |
566 |
|
|
567 |
0 |
for (loop = 0; loop < MAXARGS; loop++) { |
568 |
0 |
if (loop < argc) { |
569 |
0 |
if (!js_ValueToNumber(cx, argv[loop], &d)) |
570 |
0 |
return JS_FALSE; |
571 |
|
/* return NaN if any arg is NaN */ |
572 |
0 |
if (!JSDOUBLE_IS_FINITE(d)) { |
573 |
0 |
return js_NewNumberValue(cx, d, rval); |
574 |
|
} |
575 |
0 |
array[loop] = floor(d); |
576 |
|
} else { |
577 |
0 |
array[loop] = 0; |
578 |
|
} |
579 |
|
} |
580 |
|
|
581 |
|
/* adjust 2-digit years into the 20th century */ |
582 |
0 |
if (array[0] >= 0 && array[0] <= 99) |
583 |
0 |
array[0] += 1900; |
584 |
|
|
585 |
|
/* if we got a 0 for 'date' (which is out of range) |
586 |
|
* pretend it's a 1. (So Date.UTC(1972, 5) works) */ |
587 |
0 |
if (array[2] < 1) |
588 |
0 |
array[2] = 1; |
589 |
|
|
590 |
0 |
d = date_msecFromDate(array[0], array[1], array[2], |
591 |
|
array[3], array[4], array[5], array[6]); |
592 |
0 |
d = TIMECLIP(d); |
593 |
|
|
594 |
0 |
return js_NewNumberValue(cx, d, rval); |
595 |
|
} |
596 |
|
|
597 |
|
static JSBool |
598 |
|
date_parseString(JSString *str, jsdouble *result) |
599 |
0 |
{ |
600 |
0 |
jsdouble msec; |
601 |
|
|
602 |
0 |
const jschar *s = JSSTRING_CHARS(str); |
603 |
0 |
size_t limit = JSSTRING_LENGTH(str); |
604 |
0 |
size_t i = 0; |
605 |
0 |
int year = -1; |
606 |
0 |
int mon = -1; |
607 |
0 |
int mday = -1; |
608 |
0 |
int hour = -1; |
609 |
0 |
int min = -1; |
610 |
0 |
int sec = -1; |
611 |
0 |
int c = -1; |
612 |
0 |
int n = -1; |
613 |
0 |
jsdouble tzoffset = -1; /* was an int, overflowed on win16!!! */ |
614 |
0 |
int prevc = 0; |
615 |
0 |
JSBool seenplusminus = JS_FALSE; |
616 |
0 |
int temp; |
617 |
0 |
JSBool seenmonthname = JS_FALSE; |
618 |
|
|
619 |
0 |
if (limit == 0) |
620 |
0 |
goto syntax; |
621 |
0 |
while (i < limit) { |
622 |
0 |
c = s[i]; |
623 |
0 |
i++; |
624 |
0 |
if (c <= ' ' || c == ',' || c == '-') { |
625 |
0 |
if (c == '-' && '0' <= s[i] && s[i] <= '9') { |
626 |
0 |
prevc = c; |
627 |
|
} |
628 |
0 |
continue; |
629 |
|
} |
630 |
0 |
if (c == '(') { /* comments) */ |
631 |
0 |
int depth = 1; |
632 |
0 |
while (i < limit) { |
633 |
0 |
c = s[i]; |
634 |
0 |
i++; |
635 |
0 |
if (c == '(') depth++; |
636 |
0 |
else if (c == ')') |
637 |
0 |
if (--depth <= 0) |
638 |
0 |
break; |
639 |
|
} |
640 |
0 |
continue; |
641 |
|
} |
642 |
0 |
if ('0' <= c && c <= '9') { |
643 |
0 |
n = c - '0'; |
644 |
0 |
while (i < limit && '0' <= (c = s[i]) && c <= '9') { |
645 |
0 |
n = n * 10 + c - '0'; |
646 |
0 |
i++; |
647 |
|
} |
648 |
|
|
649 |
|
/* allow TZA before the year, so |
650 |
|
* 'Wed Nov 05 21:49:11 GMT-0800 1997' |
651 |
|
* works */ |
652 |
|
|
653 |
|
/* uses of seenplusminus allow : in TZA, so Java |
654 |
|
* no-timezone style of GMT+4:30 works |
655 |
|
*/ |
656 |
|
|
657 |
0 |
if ((prevc == '+' || prevc == '-')/* && year>=0 */) { |
658 |
|
/* make ':' case below change tzoffset */ |
659 |
0 |
seenplusminus = JS_TRUE; |
660 |
|
|
661 |
|
/* offset */ |
662 |
0 |
if (n < 24) |
663 |
0 |
n = n * 60; /* EG. "GMT-3" */ |
664 |
|
else |
665 |
0 |
n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */ |
666 |
0 |
if (prevc == '+') /* plus means east of GMT */ |
667 |
0 |
n = -n; |
668 |
0 |
if (tzoffset != 0 && tzoffset != -1) |
669 |
0 |
goto syntax; |
670 |
0 |
tzoffset = n; |
671 |
0 |
} else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) { |
672 |
0 |
if (c <= ' ' || c == ',' || c == '/' || i >= limit) |
673 |
0 |
year = n; |
674 |
|
else |
675 |
0 |
goto syntax; |
676 |
0 |
} else if (c == ':') { |
677 |
0 |
if (hour < 0) |
678 |
0 |
hour = /*byte*/ n; |
679 |
0 |
else if (min < 0) |
680 |
0 |
min = /*byte*/ n; |
681 |
|
else |
682 |
0 |
goto syntax; |
683 |
0 |
} else if (c == '/') { |
684 |
|
/* until it is determined that mon is the actual |
685 |
|
month, keep it as 1-based rather than 0-based */ |
686 |
0 |
if (mon < 0) |
687 |
0 |
mon = /*byte*/ n; |
688 |
0 |
else if (mday < 0) |
689 |
0 |
mday = /*byte*/ n; |
690 |
|
else |
691 |
0 |
goto syntax; |
692 |
0 |
} else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') { |
693 |
0 |
goto syntax; |
694 |
0 |
} else if (seenplusminus && n < 60) { /* handle GMT-3:30 */ |
695 |
0 |
if (tzoffset < 0) |
696 |
0 |
tzoffset -= n; |
697 |
|
else |
698 |
0 |
tzoffset += n; |
699 |
0 |
} else if (hour >= 0 && min < 0) { |
700 |
0 |
min = /*byte*/ n; |
701 |
0 |
} else if (prevc == ':' && min >= 0 && sec < 0) { |
702 |
0 |
sec = /*byte*/ n; |
703 |
0 |
} else if (mon < 0) { |
704 |
0 |
mon = /*byte*/n; |
705 |
0 |
} else if (mon >= 0 && mday < 0) { |
706 |
0 |
mday = /*byte*/ n; |
707 |
0 |
} else if (mon >= 0 && mday >= 0 && year < 0) { |
708 |
0 |
year = n; |
709 |
|
} else { |
710 |
0 |
goto syntax; |
711 |
|
} |
712 |
0 |
prevc = 0; |
713 |
0 |
} else if (c == '/' || c == ':' || c == '+' || c == '-') { |
714 |
0 |
prevc = c; |
715 |
|
} else { |
716 |
0 |
size_t st = i - 1; |
717 |
0 |
int k; |
718 |
0 |
while (i < limit) { |
719 |
0 |
c = s[i]; |
720 |
0 |
if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) |
721 |
0 |
break; |
722 |
0 |
i++; |
723 |
|
} |
724 |
0 |
if (i <= st + 1) |
725 |
0 |
goto syntax; |
726 |
0 |
for (k = (sizeof(wtb)/sizeof(char*)); --k >= 0;) |
727 |
0 |
if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) { |
728 |
0 |
int action = ttb[k]; |
729 |
0 |
if (action != 0) { |
730 |
0 |
if (action < 0) { |
731 |
|
/* |
732 |
|
* AM/PM. Count 12:30 AM as 00:30, 12:30 PM as |
733 |
|
* 12:30, instead of blindly adding 12 if PM. |
734 |
|
*/ |
735 |
0 |
JS_ASSERT(action == -1 || action == -2); |
736 |
0 |
if (hour > 12 || hour < 0) { |
737 |
0 |
goto syntax; |
738 |
|
} else { |
739 |
0 |
if (action == -1 && hour == 12) { /* am */ |
740 |
0 |
hour = 0; |
741 |
0 |
} else if (action == -2 && hour != 12) { /* pm */ |
742 |
0 |
hour += 12; |
743 |
|
} |
744 |
|
} |
745 |
0 |
} else if (action <= 13) { /* month! */ |
746 |
|
/* Adjust mon to be 1-based until the final values |
747 |
|
for mon, mday and year are adjusted below */ |
748 |
0 |
if (seenmonthname) { |
749 |
0 |
goto syntax; |
750 |
|
} |
751 |
0 |
seenmonthname = JS_TRUE; |
752 |
0 |
temp = /*byte*/ (action - 2) + 1; |
753 |
|
|
754 |
0 |
if (mon < 0) { |
755 |
0 |
mon = temp; |
756 |
0 |
} else if (mday < 0) { |
757 |
0 |
mday = mon; |
758 |
0 |
mon = temp; |
759 |
0 |
} else if (year < 0) { |
760 |
0 |
year = mon; |
761 |
0 |
mon = temp; |
762 |
|
} else { |
763 |
0 |
goto syntax; |
764 |
|
} |
765 |
|
} else { |
766 |
0 |
tzoffset = action - 10000; |
767 |
|
} |
768 |
|
} |
769 |
|
break; |
770 |
|
} |
771 |
0 |
if (k < 0) |
772 |
0 |
goto syntax; |
773 |
0 |
prevc = 0; |
774 |
|
} |
775 |
|
} |
776 |
0 |
if (year < 0 || mon < 0 || mday < 0) |
777 |
0 |
goto syntax; |
778 |
|
/* |
779 |
|
Case 1. The input string contains an English month name. |
780 |
|
The form of the string can be month f l, or f month l, or |
781 |
|
f l month which each evaluate to the same date. |
782 |
|
If f and l are both greater than or equal to 70, or |
783 |
|
both less than 70, the date is invalid. |
784 |
|
The year is taken to be the greater of the values f, l. |
785 |
|
If the year is greater than or equal to 70 and less than 100, |
786 |
|
it is considered to be the number of years after 1900. |
787 |
|
Case 2. The input string is of the form "f/m/l" where f, m and l are |
788 |
|
integers, e.g. 7/16/45. |
789 |
|
Adjust the mon, mday and year values to achieve 100% MSIE |
790 |
|
compatibility. |
791 |
|
a. If 0 <= f < 70, f/m/l is interpreted as month/day/year. |
792 |
|
i. If year < 100, it is the number of years after 1900 |
793 |
|
ii. If year >= 100, it is the number of years after 0. |
794 |
|
b. If 70 <= f < 100 |
795 |
|
i. If m < 70, f/m/l is interpreted as |
796 |
|
year/month/day where year is the number of years after |
797 |
|
1900. |
798 |
|
ii. If m >= 70, the date is invalid. |
799 |
|
c. If f >= 100 |
800 |
|
i. If m < 70, f/m/l is interpreted as |
801 |
|
year/month/day where year is the number of years after 0. |
802 |
|
ii. If m >= 70, the date is invalid. |
803 |
|
*/ |
804 |
0 |
if (seenmonthname) { |
805 |
0 |
if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) { |
806 |
0 |
goto syntax; |
807 |
|
} |
808 |
0 |
if (mday > year) { |
809 |
0 |
temp = year; |
810 |
0 |
year = mday; |
811 |
0 |
mday = temp; |
812 |
|
} |
813 |
0 |
if (year >= 70 && year < 100) { |
814 |
0 |
year += 1900; |
815 |
|
} |
816 |
0 |
} else if (mon < 70) { /* (a) month/day/year */ |
817 |
0 |
if (year < 100) { |
818 |
0 |
year += 1900; |
819 |
|
} |
820 |
0 |
} else if (mon < 100) { /* (b) year/month/day */ |
821 |
0 |
if (mday < 70) { |
822 |
0 |
temp = year; |
823 |
0 |
year = mon + 1900; |
824 |
0 |
mon = mday; |
825 |
0 |
mday = temp; |
826 |
|
} else { |
827 |
0 |
goto syntax; |
828 |
|
} |
829 |
|
} else { /* (c) year/month/day */ |
830 |
0 |
if (mday < 70) { |
831 |
0 |
temp = year; |
832 |
0 |
year = mon; |
833 |
0 |
mon = mday; |
834 |
0 |
mday = temp; |
835 |
|
} else { |
836 |
0 |
goto syntax; |
837 |
|
} |
838 |
|
} |
839 |
0 |
mon -= 1; /* convert month to 0-based */ |
840 |
0 |
if (sec < 0) |
841 |
0 |
sec = 0; |
842 |
0 |
if (min < 0) |
843 |
0 |
min = 0; |
844 |
0 |
if (hour < 0) |
845 |
0 |
hour = 0; |
846 |
0 |
if (tzoffset == -1) { /* no time zone specified, have to use local */ |
847 |
0 |
jsdouble msec_time; |
848 |
0 |
msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); |
849 |
|
|
850 |
0 |
*result = UTC(msec_time); |
851 |
0 |
return JS_TRUE; |
852 |
|
} |
853 |
|
|
854 |
0 |
msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0); |
855 |
0 |
msec += tzoffset * msPerMinute; |
856 |
0 |
*result = msec; |
857 |
0 |
return JS_TRUE; |
858 |
|
|
859 |
|
syntax: |
860 |
|
/* syntax error */ |
861 |
0 |
*result = 0; |
862 |
0 |
return JS_FALSE; |
863 |
|
} |
864 |
|
|
865 |
|
static JSBool |
866 |
|
date_parse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
867 |
0 |
{ |
868 |
0 |
JSString *str; |
869 |
0 |
jsdouble result; |
870 |
|
|
871 |
0 |
str = js_ValueToString(cx, argv[0]); |
872 |
0 |
if (!str) |
873 |
0 |
return JS_FALSE; |
874 |
0 |
if (!date_parseString(str, &result)) { |
875 |
0 |
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); |
876 |
0 |
return JS_TRUE; |
877 |
|
} |
878 |
|
|
879 |
0 |
result = TIMECLIP(result); |
880 |
0 |
return js_NewNumberValue(cx, result, rval); |
881 |
|
} |
882 |
|
|
883 |
|
static JSBool |
884 |
|
date_now(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
885 |
0 |
{ |
886 |
0 |
int64 us, ms, us2ms; |
887 |
0 |
jsdouble msec_time; |
888 |
|
|
889 |
0 |
us = PRMJ_Now(); |
890 |
0 |
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC); |
891 |
0 |
JSLL_DIV(ms, us, us2ms); |
892 |
0 |
JSLL_L2D(msec_time, ms); |
893 |
|
|
894 |
0 |
return js_NewDoubleValue(cx, msec_time, rval); |
895 |
|
} |
896 |
|
|
897 |
|
/* |
898 |
|
* Check that obj is an object of class Date, and get the date value. |
899 |
|
* Return NULL on failure. |
900 |
|
*/ |
901 |
|
static jsdouble * |
902 |
|
date_getProlog(JSContext *cx, JSObject *obj, jsval *argv) |
903 |
0 |
{ |
904 |
0 |
if (!JS_InstanceOf(cx, obj, &date_class, argv)) |
905 |
0 |
return NULL; |
906 |
0 |
return JSVAL_TO_DOUBLE(OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE)); |
907 |
|
} |
908 |
|
|
909 |
|
/* |
910 |
|
* See ECMA 15.9.5.4 thru 15.9.5.23 |
911 |
|
*/ |
912 |
|
static JSBool |
913 |
|
date_getTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
914 |
0 |
{ |
915 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
916 |
0 |
if (!date) |
917 |
0 |
return JS_FALSE; |
918 |
|
|
919 |
0 |
return js_NewNumberValue(cx, *date, rval); |
920 |
|
} |
921 |
|
|
922 |
|
static JSBool |
923 |
|
date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
924 |
0 |
{ |
925 |
0 |
jsdouble *date; |
926 |
0 |
jsdouble result; |
927 |
0 |
JSVersion version; |
928 |
|
|
929 |
0 |
date = date_getProlog(cx, obj, argv); |
930 |
0 |
if (!date) |
931 |
0 |
return JS_FALSE; |
932 |
|
|
933 |
0 |
result = *date; |
934 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
935 |
0 |
return js_NewNumberValue(cx, result, rval); |
936 |
|
|
937 |
0 |
result = YearFromTime(LocalTime(result)); |
938 |
|
|
939 |
|
/* |
940 |
|
* During the great date rewrite of 1.3, we tried to track the evolving ECMA |
941 |
|
* standard, which then had a definition of getYear which always subtracted |
942 |
|
* 1900. Which we implemented, not realizing that it was incompatible with |
943 |
|
* the old behavior... now, rather than thrash the behavior yet again, |
944 |
|
* we've decided to leave it with the - 1900 behavior and point people to |
945 |
|
* the getFullYear method. But we try to protect existing scripts that |
946 |
|
* have specified a version... |
947 |
|
*/ |
948 |
0 |
version = cx->version & JSVERSION_MASK; |
949 |
0 |
if (version == JSVERSION_1_0 || |
950 |
|
version == JSVERSION_1_1 || |
951 |
|
version == JSVERSION_1_2) |
952 |
|
{ |
953 |
0 |
if (result >= 1900 && result < 2000) |
954 |
0 |
result -= 1900; |
955 |
|
} else { |
956 |
0 |
result -= 1900; |
957 |
|
} |
958 |
0 |
return js_NewNumberValue(cx, result, rval); |
959 |
|
} |
960 |
|
|
961 |
|
static JSBool |
962 |
|
date_getFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
963 |
|
jsval *rval) |
964 |
0 |
{ |
965 |
0 |
jsdouble result; |
966 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
967 |
0 |
if (!date) |
968 |
0 |
return JS_FALSE; |
969 |
0 |
result = *date; |
970 |
|
|
971 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
972 |
0 |
return js_NewNumberValue(cx, result, rval); |
973 |
|
|
974 |
0 |
result = YearFromTime(LocalTime(result)); |
975 |
0 |
return js_NewNumberValue(cx, result, rval); |
976 |
|
} |
977 |
|
|
978 |
|
static JSBool |
979 |
|
date_getUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
980 |
|
jsval *rval) |
981 |
0 |
{ |
982 |
0 |
jsdouble result; |
983 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
984 |
0 |
if (!date) |
985 |
0 |
return JS_FALSE; |
986 |
0 |
result = *date; |
987 |
|
|
988 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
989 |
0 |
return js_NewNumberValue(cx, result, rval); |
990 |
|
|
991 |
0 |
result = YearFromTime(result); |
992 |
0 |
return js_NewNumberValue(cx, result, rval); |
993 |
|
} |
994 |
|
|
995 |
|
static JSBool |
996 |
|
date_getMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
997 |
|
jsval *rval) |
998 |
0 |
{ |
999 |
0 |
jsdouble result; |
1000 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1001 |
0 |
if (!date) |
1002 |
0 |
return JS_FALSE; |
1003 |
0 |
result = *date; |
1004 |
|
|
1005 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1006 |
0 |
return js_NewNumberValue(cx, result, rval); |
1007 |
|
|
1008 |
0 |
result = MonthFromTime(LocalTime(result)); |
1009 |
0 |
return js_NewNumberValue(cx, result, rval); |
1010 |
|
} |
1011 |
|
|
1012 |
|
static JSBool |
1013 |
|
date_getUTCMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1014 |
|
jsval *rval) |
1015 |
0 |
{ |
1016 |
0 |
jsdouble result; |
1017 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1018 |
0 |
if (!date) |
1019 |
0 |
return JS_FALSE; |
1020 |
0 |
result = *date; |
1021 |
|
|
1022 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1023 |
0 |
return js_NewNumberValue(cx, result, rval); |
1024 |
|
|
1025 |
0 |
result = MonthFromTime(result); |
1026 |
0 |
return js_NewNumberValue(cx, result, rval); |
1027 |
|
} |
1028 |
|
|
1029 |
|
static JSBool |
1030 |
|
date_getDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
1031 |
0 |
{ |
1032 |
0 |
jsdouble result; |
1033 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1034 |
0 |
if (!date) |
1035 |
0 |
return JS_FALSE; |
1036 |
0 |
result = *date; |
1037 |
|
|
1038 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1039 |
0 |
return js_NewNumberValue(cx, result, rval); |
1040 |
|
|
1041 |
0 |
result = LocalTime(result); |
1042 |
0 |
result = DateFromTime(result); |
1043 |
0 |
return js_NewNumberValue(cx, result, rval); |
1044 |
|
} |
1045 |
|
|
1046 |
|
static JSBool |
1047 |
|
date_getUTCDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1048 |
|
jsval *rval) |
1049 |
0 |
{ |
1050 |
0 |
jsdouble result; |
1051 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1052 |
0 |
if (!date) |
1053 |
0 |
return JS_FALSE; |
1054 |
0 |
result = *date; |
1055 |
|
|
1056 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1057 |
0 |
return js_NewNumberValue(cx, result, rval); |
1058 |
|
|
1059 |
0 |
result = DateFromTime(result); |
1060 |
0 |
return js_NewNumberValue(cx, result, rval); |
1061 |
|
} |
1062 |
|
|
1063 |
|
static JSBool |
1064 |
|
date_getDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
1065 |
0 |
{ |
1066 |
0 |
jsdouble result; |
1067 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1068 |
0 |
if (!date) |
1069 |
0 |
return JS_FALSE; |
1070 |
0 |
result = *date; |
1071 |
|
|
1072 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1073 |
0 |
return js_NewNumberValue(cx, result, rval); |
1074 |
|
|
1075 |
0 |
result = LocalTime(result); |
1076 |
0 |
result = WeekDay(result); |
1077 |
0 |
return js_NewNumberValue(cx, result, rval); |
1078 |
|
} |
1079 |
|
|
1080 |
|
static JSBool |
1081 |
|
date_getUTCDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1082 |
|
jsval *rval) |
1083 |
0 |
{ |
1084 |
0 |
jsdouble result; |
1085 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1086 |
0 |
if (!date) |
1087 |
0 |
return JS_FALSE; |
1088 |
0 |
result = *date; |
1089 |
|
|
1090 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1091 |
0 |
return js_NewNumberValue(cx, result, rval); |
1092 |
|
|
1093 |
0 |
result = WeekDay(result); |
1094 |
0 |
return js_NewNumberValue(cx, result, rval); |
1095 |
|
} |
1096 |
|
|
1097 |
|
static JSBool |
1098 |
|
date_getHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1099 |
|
jsval *rval) |
1100 |
0 |
{ |
1101 |
0 |
jsdouble result; |
1102 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1103 |
0 |
if (!date) |
1104 |
0 |
return JS_FALSE; |
1105 |
0 |
result = *date; |
1106 |
|
|
1107 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1108 |
0 |
return js_NewNumberValue(cx, result, rval); |
1109 |
|
|
1110 |
0 |
result = HourFromTime(LocalTime(result)); |
1111 |
0 |
return js_NewNumberValue(cx, result, rval); |
1112 |
|
} |
1113 |
|
|
1114 |
|
static JSBool |
1115 |
|
date_getUTCHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1116 |
|
jsval *rval) |
1117 |
0 |
{ |
1118 |
0 |
jsdouble result; |
1119 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1120 |
0 |
if (!date) |
1121 |
0 |
return JS_FALSE; |
1122 |
0 |
result = *date; |
1123 |
|
|
1124 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1125 |
0 |
return js_NewNumberValue(cx, result, rval); |
1126 |
|
|
1127 |
0 |
result = HourFromTime(result); |
1128 |
0 |
return js_NewNumberValue(cx, result, rval); |
1129 |
|
} |
1130 |
|
|
1131 |
|
static JSBool |
1132 |
|
date_getMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1133 |
|
jsval *rval) |
1134 |
0 |
{ |
1135 |
0 |
jsdouble result; |
1136 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1137 |
0 |
if (!date) |
1138 |
0 |
return JS_FALSE; |
1139 |
0 |
result = *date; |
1140 |
|
|
1141 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1142 |
0 |
return js_NewNumberValue(cx, result, rval); |
1143 |
|
|
1144 |
0 |
result = MinFromTime(LocalTime(result)); |
1145 |
0 |
return js_NewNumberValue(cx, result, rval); |
1146 |
|
} |
1147 |
|
|
1148 |
|
static JSBool |
1149 |
|
date_getUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1150 |
|
jsval *rval) |
1151 |
0 |
{ |
1152 |
0 |
jsdouble result; |
1153 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1154 |
0 |
if (!date) |
1155 |
0 |
return JS_FALSE; |
1156 |
0 |
result = *date; |
1157 |
|
|
1158 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1159 |
0 |
return js_NewNumberValue(cx, result, rval); |
1160 |
|
|
1161 |
0 |
result = MinFromTime(result); |
1162 |
0 |
return js_NewNumberValue(cx, result, rval); |
1163 |
|
} |
1164 |
|
|
1165 |
|
/* Date.getSeconds is mapped to getUTCSeconds */ |
1166 |
|
|
1167 |
|
static JSBool |
1168 |
|
date_getUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1169 |
|
jsval *rval) |
1170 |
0 |
{ |
1171 |
0 |
jsdouble result; |
1172 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1173 |
0 |
if (!date) |
1174 |
0 |
return JS_FALSE; |
1175 |
0 |
result = *date; |
1176 |
|
|
1177 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1178 |
0 |
return js_NewNumberValue(cx, result, rval); |
1179 |
|
|
1180 |
0 |
result = SecFromTime(result); |
1181 |
0 |
return js_NewNumberValue(cx, result, rval); |
1182 |
|
} |
1183 |
|
|
1184 |
|
/* Date.getMilliseconds is mapped to getUTCMilliseconds */ |
1185 |
|
|
1186 |
|
static JSBool |
1187 |
|
date_getUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1188 |
|
jsval *rval) |
1189 |
0 |
{ |
1190 |
0 |
jsdouble result; |
1191 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1192 |
0 |
if (!date) |
1193 |
0 |
return JS_FALSE; |
1194 |
0 |
result = *date; |
1195 |
|
|
1196 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1197 |
0 |
return js_NewNumberValue(cx, result, rval); |
1198 |
|
|
1199 |
0 |
result = msFromTime(result); |
1200 |
0 |
return js_NewNumberValue(cx, result, rval); |
1201 |
|
} |
1202 |
|
|
1203 |
|
static JSBool |
1204 |
|
date_getTimezoneOffset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1205 |
|
jsval *rval) |
1206 |
0 |
{ |
1207 |
0 |
jsdouble result; |
1208 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1209 |
0 |
if (!date) |
1210 |
0 |
return JS_FALSE; |
1211 |
0 |
result = *date; |
1212 |
|
|
1213 |
|
/* |
1214 |
|
* Return the time zone offset in minutes for the current locale |
1215 |
|
* that is appropriate for this time. This value would be a |
1216 |
|
* constant except for daylight savings time. |
1217 |
|
*/ |
1218 |
0 |
result = (result - LocalTime(result)) / msPerMinute; |
1219 |
0 |
return js_NewNumberValue(cx, result, rval); |
1220 |
|
} |
1221 |
|
|
1222 |
|
static JSBool |
1223 |
|
date_setTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
1224 |
0 |
{ |
1225 |
0 |
jsdouble result; |
1226 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1227 |
0 |
if (!date) |
1228 |
0 |
return JS_FALSE; |
1229 |
|
|
1230 |
0 |
if (!js_ValueToNumber(cx, argv[0], &result)) |
1231 |
0 |
return JS_FALSE; |
1232 |
|
|
1233 |
0 |
result = TIMECLIP(result); |
1234 |
|
|
1235 |
0 |
*date = result; |
1236 |
0 |
return js_NewNumberValue(cx, result, rval); |
1237 |
|
} |
1238 |
|
|
1239 |
|
static JSBool |
1240 |
|
date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1241 |
|
uintN maxargs, JSBool local, jsval *rval) |
1242 |
0 |
{ |
1243 |
0 |
uintN i; |
1244 |
0 |
jsdouble args[4], *argp, *stop; |
1245 |
0 |
jsdouble hour, min, sec, msec; |
1246 |
0 |
jsdouble lorutime; /* Local or UTC version of *date */ |
1247 |
|
|
1248 |
0 |
jsdouble msec_time; |
1249 |
0 |
jsdouble result; |
1250 |
|
|
1251 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1252 |
0 |
if (!date) |
1253 |
0 |
return JS_FALSE; |
1254 |
|
|
1255 |
0 |
result = *date; |
1256 |
|
|
1257 |
|
/* just return NaN if the date is already NaN */ |
1258 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) |
1259 |
0 |
return js_NewNumberValue(cx, result, rval); |
1260 |
|
|
1261 |
|
/* Satisfy the ECMA rule that if a function is called with |
1262 |
|
* fewer arguments than the specified formal arguments, the |
1263 |
|
* remaining arguments are set to undefined. Seems like all |
1264 |
|
* the Date.setWhatever functions in ECMA are only varargs |
1265 |
|
* beyond the first argument; this should be set to undefined |
1266 |
|
* if it's not given. This means that "d = new Date(); |
1267 |
|
* d.setMilliseconds()" returns NaN. Blech. |
1268 |
|
*/ |
1269 |
0 |
if (argc == 0) |
1270 |
0 |
argc = 1; /* should be safe, because length of all setters is 1 */ |
1271 |
0 |
else if (argc > maxargs) |
1272 |
0 |
argc = maxargs; /* clamp argc */ |
1273 |
|
|
1274 |
0 |
for (i = 0; i < argc; i++) { |
1275 |
0 |
if (!js_ValueToNumber(cx, argv[i], &args[i])) |
1276 |
0 |
return JS_FALSE; |
1277 |
0 |
if (!JSDOUBLE_IS_FINITE(args[i])) { |
1278 |
0 |
*date = *cx->runtime->jsNaN; |
1279 |
0 |
return js_NewNumberValue(cx, *date, rval); |
1280 |
|
} |
1281 |
0 |
args[i] = js_DoubleToInteger(args[i]); |
1282 |
|
} |
1283 |
|
|
1284 |
0 |
if (local) |
1285 |
0 |
lorutime = LocalTime(result); |
1286 |
|
else |
1287 |
0 |
lorutime = result; |
1288 |
|
|
1289 |
0 |
argp = args; |
1290 |
0 |
stop = argp + argc; |
1291 |
0 |
if (maxargs >= 4 && argp < stop) |
1292 |
0 |
hour = *argp++; |
1293 |
|
else |
1294 |
0 |
hour = HourFromTime(lorutime); |
1295 |
|
|
1296 |
0 |
if (maxargs >= 3 && argp < stop) |
1297 |
0 |
min = *argp++; |
1298 |
|
else |
1299 |
0 |
min = MinFromTime(lorutime); |
1300 |
|
|
1301 |
0 |
if (maxargs >= 2 && argp < stop) |
1302 |
0 |
sec = *argp++; |
1303 |
|
else |
1304 |
0 |
sec = SecFromTime(lorutime); |
1305 |
|
|
1306 |
0 |
if (maxargs >= 1 && argp < stop) |
1307 |
0 |
msec = *argp; |
1308 |
|
else |
1309 |
0 |
msec = msFromTime(lorutime); |
1310 |
|
|
1311 |
0 |
msec_time = MakeTime(hour, min, sec, msec); |
1312 |
0 |
result = MakeDate(Day(lorutime), msec_time); |
1313 |
|
|
1314 |
|
/* fprintf(stderr, "%f\n", result); */ |
1315 |
|
|
1316 |
0 |
if (local) |
1317 |
0 |
result = UTC(result); |
1318 |
|
|
1319 |
|
/* fprintf(stderr, "%f\n", result); */ |
1320 |
|
|
1321 |
0 |
*date = TIMECLIP(result); |
1322 |
0 |
return js_NewNumberValue(cx, *date, rval); |
1323 |
|
} |
1324 |
|
|
1325 |
|
static JSBool |
1326 |
|
date_setMilliseconds(JSContext *cx, JSObject *obj, uintN argc, |
1327 |
|
jsval *argv, jsval *rval) |
1328 |
0 |
{ |
1329 |
0 |
return date_makeTime(cx, obj, argc, argv, 1, JS_TRUE, rval); |
1330 |
|
} |
1331 |
|
|
1332 |
|
static JSBool |
1333 |
|
date_setUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, |
1334 |
|
jsval *argv, jsval *rval) |
1335 |
0 |
{ |
1336 |
0 |
return date_makeTime(cx, obj, argc, argv, 1, JS_FALSE, rval); |
1337 |
|
} |
1338 |
|
|
1339 |
|
static JSBool |
1340 |
|
date_setSeconds(JSContext *cx, JSObject *obj, uintN argc, |
1341 |
|
jsval *argv, jsval *rval) |
1342 |
0 |
{ |
1343 |
0 |
return date_makeTime(cx, obj, argc, argv, 2, JS_TRUE, rval); |
1344 |
|
} |
1345 |
|
|
1346 |
|
static JSBool |
1347 |
|
date_setUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, |
1348 |
|
jsval *argv, jsval *rval) |
1349 |
0 |
{ |
1350 |
0 |
return date_makeTime(cx, obj, argc, argv, 2, JS_FALSE, rval); |
1351 |
|
} |
1352 |
|
|
1353 |
|
static JSBool |
1354 |
|
date_setMinutes(JSContext *cx, JSObject *obj, uintN argc, |
1355 |
|
jsval *argv, jsval *rval) |
1356 |
0 |
{ |
1357 |
0 |
return date_makeTime(cx, obj, argc, argv, 3, JS_TRUE, rval); |
1358 |
|
} |
1359 |
|
|
1360 |
|
static JSBool |
1361 |
|
date_setUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, |
1362 |
|
jsval *argv, jsval *rval) |
1363 |
0 |
{ |
1364 |
0 |
return date_makeTime(cx, obj, argc, argv, 3, JS_FALSE, rval); |
1365 |
|
} |
1366 |
|
|
1367 |
|
static JSBool |
1368 |
|
date_setHours(JSContext *cx, JSObject *obj, uintN argc, |
1369 |
|
jsval *argv, jsval *rval) |
1370 |
0 |
{ |
1371 |
0 |
return date_makeTime(cx, obj, argc, argv, 4, JS_TRUE, rval); |
1372 |
|
} |
1373 |
|
|
1374 |
|
static JSBool |
1375 |
|
date_setUTCHours(JSContext *cx, JSObject *obj, uintN argc, |
1376 |
|
jsval *argv, jsval *rval) |
1377 |
0 |
{ |
1378 |
0 |
return date_makeTime(cx, obj, argc, argv, 4, JS_FALSE, rval); |
1379 |
|
} |
1380 |
|
|
1381 |
|
static JSBool |
1382 |
|
date_makeDate(JSContext *cx, JSObject *obj, uintN argc, |
1383 |
|
jsval *argv, uintN maxargs, JSBool local, jsval *rval) |
1384 |
0 |
{ |
1385 |
0 |
uintN i; |
1386 |
0 |
jsdouble lorutime; /* local or UTC version of *date */ |
1387 |
0 |
jsdouble args[3], *argp, *stop; |
1388 |
0 |
jsdouble year, month, day; |
1389 |
0 |
jsdouble result; |
1390 |
|
|
1391 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1392 |
0 |
if (!date) |
1393 |
0 |
return JS_FALSE; |
1394 |
|
|
1395 |
0 |
result = *date; |
1396 |
|
|
1397 |
|
/* see complaint about ECMA in date_MakeTime */ |
1398 |
0 |
if (argc == 0) |
1399 |
0 |
argc = 1; /* should be safe, because length of all setters is 1 */ |
1400 |
0 |
else if (argc > maxargs) |
1401 |
0 |
argc = maxargs; /* clamp argc */ |
1402 |
|
|
1403 |
0 |
for (i = 0; i < argc; i++) { |
1404 |
0 |
if (!js_ValueToNumber(cx, argv[i], &args[i])) |
1405 |
0 |
return JS_FALSE; |
1406 |
0 |
if (!JSDOUBLE_IS_FINITE(args[i])) { |
1407 |
0 |
*date = *cx->runtime->jsNaN; |
1408 |
0 |
return js_NewNumberValue(cx, *date, rval); |
1409 |
|
} |
1410 |
0 |
args[i] = js_DoubleToInteger(args[i]); |
1411 |
|
} |
1412 |
|
|
1413 |
|
/* return NaN if date is NaN and we're not setting the year, |
1414 |
|
* If we are, use 0 as the time. */ |
1415 |
0 |
if (!(JSDOUBLE_IS_FINITE(result))) { |
1416 |
0 |
if (argc < 3) |
1417 |
0 |
return js_NewNumberValue(cx, result, rval); |
1418 |
|
else |
1419 |
0 |
lorutime = +0.; |
1420 |
|
} else { |
1421 |
0 |
if (local) |
1422 |
0 |
lorutime = LocalTime(result); |
1423 |
|
else |
1424 |
0 |
lorutime = result; |
1425 |
|
} |
1426 |
|
|
1427 |
0 |
argp = args; |
1428 |
0 |
stop = argp + argc; |
1429 |
0 |
if (maxargs >= 3 && argp < stop) |
1430 |
0 |
year = *argp++; |
1431 |
|
else |
1432 |
0 |
year = YearFromTime(lorutime); |
1433 |
|
|
1434 |
0 |
if (maxargs >= 2 && argp < stop) |
1435 |
0 |
month = *argp++; |
1436 |
|
else |
1437 |
0 |
month = MonthFromTime(lorutime); |
1438 |
|
|
1439 |
0 |
if (maxargs >= 1 && argp < stop) |
1440 |
0 |
day = *argp++; |
1441 |
|
else |
1442 |
0 |
day = DateFromTime(lorutime); |
1443 |
|
|
1444 |
0 |
day = MakeDay(year, month, day); /* day within year */ |
1445 |
0 |
result = MakeDate(day, TimeWithinDay(lorutime)); |
1446 |
|
|
1447 |
0 |
if (local) |
1448 |
0 |
result = UTC(result); |
1449 |
|
|
1450 |
0 |
*date = TIMECLIP(result); |
1451 |
0 |
return js_NewNumberValue(cx, *date, rval); |
1452 |
|
} |
1453 |
|
|
1454 |
|
static JSBool |
1455 |
|
date_setDate(JSContext *cx, JSObject *obj, uintN argc, |
1456 |
|
jsval *argv, jsval *rval) |
1457 |
0 |
{ |
1458 |
0 |
return date_makeDate(cx, obj, argc, argv, 1, JS_TRUE, rval); |
1459 |
|
} |
1460 |
|
|
1461 |
|
static JSBool |
1462 |
|
date_setUTCDate(JSContext *cx, JSObject *obj, uintN argc, |
1463 |
|
jsval *argv, jsval *rval) |
1464 |
0 |
{ |
1465 |
0 |
return date_makeDate(cx, obj, argc, argv, 1, JS_FALSE, rval); |
1466 |
|
} |
1467 |
|
|
1468 |
|
static JSBool |
1469 |
|
date_setMonth(JSContext *cx, JSObject *obj, uintN argc, |
1470 |
|
jsval *argv, jsval *rval) |
1471 |
0 |
{ |
1472 |
0 |
return date_makeDate(cx, obj, argc, argv, 2, JS_TRUE, rval); |
1473 |
|
} |
1474 |
|
|
1475 |
|
static JSBool |
1476 |
|
date_setUTCMonth(JSContext *cx, JSObject *obj, uintN argc, |
1477 |
|
jsval *argv, jsval *rval) |
1478 |
0 |
{ |
1479 |
0 |
return date_makeDate(cx, obj, argc, argv, 2, JS_FALSE, rval); |
1480 |
|
} |
1481 |
|
|
1482 |
|
static JSBool |
1483 |
|
date_setFullYear(JSContext *cx, JSObject *obj, uintN argc, |
1484 |
|
jsval *argv, jsval *rval) |
1485 |
0 |
{ |
1486 |
0 |
return date_makeDate(cx, obj, argc, argv, 3, JS_TRUE, rval); |
1487 |
|
} |
1488 |
|
|
1489 |
|
static JSBool |
1490 |
|
date_setUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, |
1491 |
|
jsval *argv, jsval *rval) |
1492 |
0 |
{ |
1493 |
0 |
return date_makeDate(cx, obj, argc, argv, 3, JS_FALSE, rval); |
1494 |
|
} |
1495 |
|
|
1496 |
|
static JSBool |
1497 |
|
date_setYear(JSContext *cx, JSObject *obj, uintN argc, |
1498 |
|
jsval *argv, jsval *rval) |
1499 |
0 |
{ |
1500 |
0 |
jsdouble t; |
1501 |
0 |
jsdouble year; |
1502 |
0 |
jsdouble day; |
1503 |
0 |
jsdouble result; |
1504 |
|
|
1505 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1506 |
0 |
if (!date) |
1507 |
0 |
return JS_FALSE; |
1508 |
|
|
1509 |
0 |
result = *date; |
1510 |
|
|
1511 |
0 |
if (!js_ValueToNumber(cx, argv[0], &year)) |
1512 |
0 |
return JS_FALSE; |
1513 |
0 |
if (!JSDOUBLE_IS_FINITE(year)) { |
1514 |
0 |
*date = *cx->runtime->jsNaN; |
1515 |
0 |
return js_NewNumberValue(cx, *date, rval); |
1516 |
|
} |
1517 |
|
|
1518 |
0 |
year = js_DoubleToInteger(year); |
1519 |
|
|
1520 |
0 |
if (!JSDOUBLE_IS_FINITE(result)) { |
1521 |
0 |
t = +0.0; |
1522 |
|
} else { |
1523 |
0 |
t = LocalTime(result); |
1524 |
|
} |
1525 |
|
|
1526 |
0 |
if (year >= 0 && year <= 99) |
1527 |
0 |
year += 1900; |
1528 |
|
|
1529 |
0 |
day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); |
1530 |
0 |
result = MakeDate(day, TimeWithinDay(t)); |
1531 |
0 |
result = UTC(result); |
1532 |
|
|
1533 |
0 |
*date = TIMECLIP(result); |
1534 |
0 |
return js_NewNumberValue(cx, *date, rval); |
1535 |
|
} |
1536 |
|
|
1537 |
|
/* constants for toString, toUTCString */ |
1538 |
|
static char js_NaN_date_str[] = "Invalid Date"; |
1539 |
|
static const char* days[] = |
1540 |
|
{ |
1541 |
|
"Sun","Mon","Tue","Wed","Thu","Fri","Sat" |
1542 |
|
}; |
1543 |
|
static const char* months[] = |
1544 |
|
{ |
1545 |
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
1546 |
|
}; |
1547 |
|
|
1548 |
|
static JSBool |
1549 |
|
date_toGMTString(JSContext *cx, JSObject *obj, uintN argc, |
1550 |
|
jsval *argv, jsval *rval) |
1551 |
0 |
{ |
1552 |
0 |
char buf[100]; |
1553 |
0 |
JSString *str; |
1554 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1555 |
0 |
if (!date) |
1556 |
0 |
return JS_FALSE; |
1557 |
|
|
1558 |
0 |
if (!JSDOUBLE_IS_FINITE(*date)) { |
1559 |
0 |
JS_snprintf(buf, sizeof buf, js_NaN_date_str); |
1560 |
|
} else { |
1561 |
0 |
jsdouble temp = *date; |
1562 |
|
|
1563 |
|
/* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it |
1564 |
|
* requires a PRMJTime... which only has 16-bit years. Sub-ECMA. |
1565 |
|
*/ |
1566 |
0 |
JS_snprintf(buf, sizeof buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", |
1567 |
|
days[WeekDay(temp)], |
1568 |
|
DateFromTime(temp), |
1569 |
|
months[MonthFromTime(temp)], |
1570 |
|
YearFromTime(temp), |
1571 |
|
HourFromTime(temp), |
1572 |
|
MinFromTime(temp), |
1573 |
|
SecFromTime(temp)); |
1574 |
|
} |
1575 |
0 |
str = JS_NewStringCopyZ(cx, buf); |
1576 |
0 |
if (!str) |
1577 |
0 |
return JS_FALSE; |
1578 |
0 |
*rval = STRING_TO_JSVAL(str); |
1579 |
0 |
return JS_TRUE; |
1580 |
|
} |
1581 |
|
|
1582 |
|
/* for Date.toLocaleString; interface to PRMJTime date struct. |
1583 |
|
* If findEquivalent is true, then try to map the year to an equivalent year |
1584 |
|
* that's in range. |
1585 |
|
*/ |
1586 |
|
static void |
1587 |
|
new_explode(jsdouble timeval, PRMJTime *split, JSBool findEquivalent) |
1588 |
0 |
{ |
1589 |
0 |
jsint year = YearFromTime(timeval); |
1590 |
0 |
int16 adjustedYear; |
1591 |
|
|
1592 |
|
/* If the year doesn't fit in a PRMJTime, find something to do about it. */ |
1593 |
0 |
if (year > 32767 || year < -32768) { |
1594 |
0 |
if (findEquivalent) { |
1595 |
|
/* We're really just trying to get a timezone string; map the year |
1596 |
|
* to some equivalent year in the range 0 to 2800. Borrowed from |
1597 |
|
* A. D. Olsen. |
1598 |
|
*/ |
1599 |
0 |
jsint cycles; |
1600 |
|
#define CYCLE_YEARS 2800L |
1601 |
0 |
cycles = (year >= 0) ? year / CYCLE_YEARS |
1602 |
|
: -1 - (-1 - year) / CYCLE_YEARS; |
1603 |
0 |
adjustedYear = (int16)(year - cycles * CYCLE_YEARS); |
1604 |
|
} else { |
1605 |
|
/* Clamp it to the nearest representable year. */ |
1606 |
0 |
adjustedYear = (int16)((year > 0) ? 32767 : - 32768); |
1607 |
|
} |
1608 |
|
} else { |
1609 |
0 |
adjustedYear = (int16)year; |
1610 |
|
} |
1611 |
|
|
1612 |
0 |
split->tm_usec = (int32) msFromTime(timeval) * 1000; |
1613 |
0 |
split->tm_sec = (int8) SecFromTime(timeval); |
1614 |
0 |
split->tm_min = (int8) MinFromTime(timeval); |
1615 |
0 |
split->tm_hour = (int8) HourFromTime(timeval); |
1616 |
0 |
split->tm_mday = (int8) DateFromTime(timeval); |
1617 |
0 |
split->tm_mon = (int8) MonthFromTime(timeval); |
1618 |
0 |
split->tm_wday = (int8) WeekDay(timeval); |
1619 |
0 |
split->tm_year = (int16) adjustedYear; |
1620 |
0 |
split->tm_yday = (int16) DayWithinYear(timeval, year); |
1621 |
|
|
1622 |
|
/* not sure how this affects things, but it doesn't seem |
1623 |
|
to matter. */ |
1624 |
0 |
split->tm_isdst = (DaylightSavingTA(timeval) != 0); |
1625 |
|
} |
1626 |
|
|
1627 |
|
typedef enum formatspec { |
1628 |
|
FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME |
1629 |
|
} formatspec; |
1630 |
|
|
1631 |
|
/* helper function */ |
1632 |
|
static JSBool |
1633 |
|
date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval) |
1634 |
0 |
{ |
1635 |
0 |
char buf[100]; |
1636 |
0 |
JSString *str; |
1637 |
0 |
char tzbuf[100]; |
1638 |
0 |
JSBool usetz; |
1639 |
0 |
size_t i, tzlen; |
1640 |
0 |
PRMJTime split; |
1641 |
|
|
1642 |
0 |
if (!JSDOUBLE_IS_FINITE(date)) { |
1643 |
0 |
JS_snprintf(buf, sizeof buf, js_NaN_date_str); |
1644 |
|
} else { |
1645 |
0 |
jsdouble local = LocalTime(date); |
1646 |
|
|
1647 |
|
/* offset from GMT in minutes. The offset includes daylight savings, |
1648 |
|
if it applies. */ |
1649 |
0 |
jsint minutes = (jsint) floor(AdjustTime(date) / msPerMinute); |
1650 |
|
|
1651 |
|
/* map 510 minutes to 0830 hours */ |
1652 |
0 |
intN offset = (minutes / 60) * 100 + minutes % 60; |
1653 |
|
|
1654 |
|
/* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is |
1655 |
|
* printed as 'GMT-0800' rather than as 'PST' to avoid |
1656 |
|
* operating-system dependence on strftime (which |
1657 |
|
* PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints |
1658 |
|
* PST as 'Pacific Standard Time.' This way we always know |
1659 |
|
* what we're getting, and can parse it if we produce it. |
1660 |
|
* The OS TZA string is included as a comment. |
1661 |
|
*/ |
1662 |
|
|
1663 |
|
/* get a timezone string from the OS to include as a |
1664 |
|
comment. */ |
1665 |
0 |
new_explode(date, &split, JS_TRUE); |
1666 |
0 |
if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) { |
1667 |
|
|
1668 |
|
/* Decide whether to use the resulting timezone string. |
1669 |
|
* |
1670 |
|
* Reject it if it contains any non-ASCII, non-alphanumeric |
1671 |
|
* characters. It's then likely in some other character |
1672 |
|
* encoding, and we probably won't display it correctly. |
1673 |
|
*/ |
1674 |
0 |
usetz = JS_TRUE; |
1675 |
0 |
tzlen = strlen(tzbuf); |
1676 |
0 |
if (tzlen > 100) { |
1677 |
0 |
usetz = JS_FALSE; |
1678 |
|
} else { |
1679 |
0 |
for (i = 0; i < tzlen; i++) { |
1680 |
0 |
jschar c = tzbuf[i]; |
1681 |
0 |
if (c > 127 || |
1682 |
|
!(isalpha(c) || isdigit(c) || |
1683 |
|
c == ' ' || c == '(' || c == ')')) { |
1684 |
0 |
usetz = JS_FALSE; |
1685 |
|
} |
1686 |
|
} |
1687 |
|
} |
1688 |
|
|
1689 |
|
/* Also reject it if it's not parenthesized or if it's '()'. */ |
1690 |
0 |
if (tzbuf[0] != '(' || tzbuf[1] == ')') |
1691 |
0 |
usetz = JS_FALSE; |
1692 |
|
} else |
1693 |
0 |
usetz = JS_FALSE; |
1694 |
|
|
1695 |
0 |
switch (format) { |
1696 |
|
case FORMATSPEC_FULL: |
1697 |
|
/* |
1698 |
|
* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it |
1699 |
|
* requires a PRMJTime... which only has 16-bit years. Sub-ECMA. |
1700 |
|
*/ |
1701 |
|
/* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */ |
1702 |
0 |
JS_snprintf(buf, sizeof buf, |
1703 |
|
"%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s", |
1704 |
|
days[WeekDay(local)], |
1705 |
|
months[MonthFromTime(local)], |
1706 |
|
DateFromTime(local), |
1707 |
|
YearFromTime(local), |
1708 |
|
HourFromTime(local), |
1709 |
|
MinFromTime(local), |
1710 |
|
SecFromTime(local), |
1711 |
|
offset, |
1712 |
|
usetz ? " " : "", |
1713 |
|
usetz ? tzbuf : ""); |
1714 |
0 |
break; |
1715 |
|
case FORMATSPEC_DATE: |
1716 |
|
/* Tue Oct 31 2000 */ |
1717 |
0 |
JS_snprintf(buf, sizeof buf, |
1718 |
|
"%s %s %.2d %.4d", |
1719 |
|
days[WeekDay(local)], |
1720 |
|
months[MonthFromTime(local)], |
1721 |
|
DateFromTime(local), |
1722 |
|
YearFromTime(local)); |
1723 |
0 |
break; |
1724 |
|
case FORMATSPEC_TIME: |
1725 |
|
/* 09:41:40 GMT-0800 (PST) */ |
1726 |
0 |
JS_snprintf(buf, sizeof buf, |
1727 |
|
"%.2d:%.2d:%.2d GMT%+.4d%s%s", |
1728 |
|
HourFromTime(local), |
1729 |
|
MinFromTime(local), |
1730 |
|
SecFromTime(local), |
1731 |
|
offset, |
1732 |
|
usetz ? " " : "", |
1733 |
|
usetz ? tzbuf : ""); |
1734 |
|
break; |
1735 |
|
} |
1736 |
|
} |
1737 |
|
|
1738 |
0 |
str = JS_NewStringCopyZ(cx, buf); |
1739 |
0 |
if (!str) |
1740 |
0 |
return JS_FALSE; |
1741 |
0 |
*rval = STRING_TO_JSVAL(str); |
1742 |
0 |
return JS_TRUE; |
1743 |
|
} |
1744 |
|
|
1745 |
|
static JSBool |
1746 |
|
date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc, |
1747 |
|
jsval *argv, jsval *rval, char *format) |
1748 |
0 |
{ |
1749 |
0 |
char buf[100]; |
1750 |
0 |
JSString *str; |
1751 |
0 |
PRMJTime split; |
1752 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1753 |
0 |
if (!date) |
1754 |
0 |
return JS_FALSE; |
1755 |
|
|
1756 |
0 |
if (!JSDOUBLE_IS_FINITE(*date)) { |
1757 |
0 |
JS_snprintf(buf, sizeof buf, js_NaN_date_str); |
1758 |
|
} else { |
1759 |
0 |
intN result_len; |
1760 |
0 |
jsdouble local = LocalTime(*date); |
1761 |
0 |
new_explode(local, &split, JS_FALSE); |
1762 |
|
|
1763 |
|
/* let PRMJTime format it. */ |
1764 |
0 |
result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split); |
1765 |
|
|
1766 |
|
/* If it failed, default to toString. */ |
1767 |
0 |
if (result_len == 0) |
1768 |
0 |
return date_format(cx, *date, FORMATSPEC_FULL, rval); |
1769 |
|
|
1770 |
|
/* Hacked check against undesired 2-digit year 00/00/00 form. */ |
1771 |
0 |
if (buf[result_len - 3] == '/' && |
1772 |
|
isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1])) { |
1773 |
0 |
JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2), |
1774 |
|
"%d", js_DateGetYear(cx, obj)); |
1775 |
|
} |
1776 |
|
|
1777 |
|
} |
1778 |
|
|
1779 |
0 |
if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) |
1780 |
0 |
return cx->localeCallbacks->localeToUnicode(cx, buf, rval); |
1781 |
|
|
1782 |
0 |
str = JS_NewStringCopyZ(cx, buf); |
1783 |
0 |
if (!str) |
1784 |
0 |
return JS_FALSE; |
1785 |
0 |
*rval = STRING_TO_JSVAL(str); |
1786 |
0 |
return JS_TRUE; |
1787 |
|
} |
1788 |
|
|
1789 |
|
static JSBool |
1790 |
|
date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, |
1791 |
|
jsval *argv, jsval *rval) |
1792 |
0 |
{ |
1793 |
|
/* Use '%#c' for windows, because '%c' is |
1794 |
|
* backward-compatible and non-y2k with msvc; '%#c' requests that a |
1795 |
|
* full year be used in the result string. |
1796 |
|
*/ |
1797 |
0 |
return date_toLocaleHelper(cx, obj, argc, argv, rval, |
1798 |
|
#if defined(_WIN32) && !defined(__MWERKS__) |
1799 |
|
"%#c" |
1800 |
|
#else |
1801 |
|
"%c" |
1802 |
|
#endif |
1803 |
|
); |
1804 |
|
} |
1805 |
|
|
1806 |
|
static JSBool |
1807 |
|
date_toLocaleDateString(JSContext *cx, JSObject *obj, uintN argc, |
1808 |
|
jsval *argv, jsval *rval) |
1809 |
0 |
{ |
1810 |
|
/* Use '%#x' for windows, because '%x' is |
1811 |
|
* backward-compatible and non-y2k with msvc; '%#x' requests that a |
1812 |
|
* full year be used in the result string. |
1813 |
|
*/ |
1814 |
0 |
return date_toLocaleHelper(cx, obj, argc, argv, rval, |
1815 |
|
#if defined(_WIN32) && !defined(__MWERKS__) |
1816 |
|
"%#x" |
1817 |
|
#else |
1818 |
|
"%x" |
1819 |
|
#endif |
1820 |
|
); |
1821 |
|
} |
1822 |
|
|
1823 |
|
static JSBool |
1824 |
|
date_toLocaleTimeString(JSContext *cx, JSObject *obj, uintN argc, |
1825 |
|
jsval *argv, jsval *rval) |
1826 |
0 |
{ |
1827 |
0 |
return date_toLocaleHelper(cx, obj, argc, argv, rval, "%X"); |
1828 |
|
} |
1829 |
|
|
1830 |
|
static JSBool |
1831 |
|
date_toLocaleFormat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1832 |
|
jsval *rval) |
1833 |
0 |
{ |
1834 |
0 |
JSString *fmt; |
1835 |
|
|
1836 |
0 |
if (argc == 0) |
1837 |
0 |
return date_toLocaleString(cx, obj, argc, argv, rval); |
1838 |
|
|
1839 |
0 |
fmt = JS_ValueToString(cx, argv[0]); |
1840 |
0 |
if (!fmt) |
1841 |
0 |
return JS_FALSE; |
1842 |
|
|
1843 |
0 |
return date_toLocaleHelper(cx, obj, argc, argv, rval, |
1844 |
|
JS_GetStringBytes(fmt)); |
1845 |
|
} |
1846 |
|
|
1847 |
|
static JSBool |
1848 |
|
date_toTimeString(JSContext *cx, JSObject *obj, uintN argc, |
1849 |
|
jsval *argv, jsval *rval) |
1850 |
0 |
{ |
1851 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1852 |
0 |
if (!date) |
1853 |
0 |
return JS_FALSE; |
1854 |
0 |
return date_format(cx, *date, FORMATSPEC_TIME, rval); |
1855 |
|
} |
1856 |
|
|
1857 |
|
static JSBool |
1858 |
|
date_toDateString(JSContext *cx, JSObject *obj, uintN argc, |
1859 |
|
jsval *argv, jsval *rval) |
1860 |
0 |
{ |
1861 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1862 |
0 |
if (!date) |
1863 |
0 |
return JS_FALSE; |
1864 |
0 |
return date_format(cx, *date, FORMATSPEC_DATE, rval); |
1865 |
|
} |
1866 |
|
|
1867 |
|
#if JS_HAS_TOSOURCE |
1868 |
|
#include <string.h> |
1869 |
|
#include "jsdtoa.h" |
1870 |
|
|
1871 |
|
static JSBool |
1872 |
|
date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1873 |
|
jsval *rval) |
1874 |
0 |
{ |
1875 |
0 |
jsdouble *date; |
1876 |
0 |
char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes; |
1877 |
0 |
JSString *str; |
1878 |
|
|
1879 |
0 |
date = date_getProlog(cx, obj, argv); |
1880 |
0 |
if (!date) |
1881 |
0 |
return JS_FALSE; |
1882 |
|
|
1883 |
0 |
numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, *date); |
1884 |
0 |
if (!numStr) { |
1885 |
0 |
JS_ReportOutOfMemory(cx); |
1886 |
0 |
return JS_FALSE; |
1887 |
|
} |
1888 |
|
|
1889 |
0 |
bytes = JS_smprintf("(new %s(%s))", date_class.name, numStr); |
1890 |
0 |
if (!bytes) { |
1891 |
0 |
JS_ReportOutOfMemory(cx); |
1892 |
0 |
return JS_FALSE; |
1893 |
|
} |
1894 |
|
|
1895 |
0 |
str = JS_NewString(cx, bytes, strlen(bytes)); |
1896 |
0 |
if (!str) { |
1897 |
0 |
free(bytes); |
1898 |
0 |
return JS_FALSE; |
1899 |
|
} |
1900 |
0 |
*rval = STRING_TO_JSVAL(str); |
1901 |
0 |
return JS_TRUE; |
1902 |
|
} |
1903 |
|
#endif |
1904 |
|
|
1905 |
|
static JSBool |
1906 |
|
date_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1907 |
|
jsval *rval) |
1908 |
0 |
{ |
1909 |
0 |
jsdouble *date = date_getProlog(cx, obj, argv); |
1910 |
0 |
if (!date) |
1911 |
0 |
return JS_FALSE; |
1912 |
0 |
return date_format(cx, *date, FORMATSPEC_FULL, rval); |
1913 |
|
} |
1914 |
|
|
1915 |
|
#if JS_HAS_VALUEOF_HINT |
1916 |
|
static JSBool |
1917 |
|
date_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
1918 |
|
jsval *rval) |
1919 |
0 |
{ |
1920 |
|
/* It is an error to call date_valueOf on a non-date object, but we don't |
1921 |
|
* need to check for that explicitly here because every path calls |
1922 |
|
* date_getProlog, which does the check. |
1923 |
|
*/ |
1924 |
|
|
1925 |
|
/* If called directly with no arguments, convert to a time number. */ |
1926 |
0 |
if (argc == 0) |
1927 |
0 |
return date_getTime(cx, obj, argc, argv, rval); |
1928 |
|
|
1929 |
|
/* Convert to number only if the hint was given, otherwise favor string. */ |
1930 |
0 |
if (argc == 1) { |
1931 |
0 |
JSString *str, *str2; |
1932 |
|
|
1933 |
0 |
str = js_ValueToString(cx, argv[0]); |
1934 |
0 |
if (!str) |
1935 |
0 |
return JS_FALSE; |
1936 |
0 |
str2 = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); |
1937 |
0 |
if (!js_CompareStrings(str, str2)) |
1938 |
0 |
return date_getTime(cx, obj, argc, argv, rval); |
1939 |
|
} |
1940 |
0 |
return date_toString(cx, obj, argc, argv, rval); |
1941 |
|
} |
1942 |
|
#else |
1943 |
|
#define date_valueOf date_getTime |
1944 |
|
#endif |
1945 |
|
|
1946 |
|
|
1947 |
|
/* |
1948 |
|
* creation and destruction |
1949 |
|
*/ |
1950 |
|
|
1951 |
|
static JSFunctionSpec date_static_methods[] = { |
1952 |
|
{"UTC", date_UTC, MAXARGS,0,0 }, |
1953 |
|
{"parse", date_parse, 1,0,0 }, |
1954 |
|
{"now", date_now, 0,0,0 }, |
1955 |
|
{0,0,0,0,0} |
1956 |
|
}; |
1957 |
|
|
1958 |
|
static JSFunctionSpec date_methods[] = { |
1959 |
|
{"getTime", date_getTime, 0,0,0 }, |
1960 |
|
{"getTimezoneOffset", date_getTimezoneOffset, 0,0,0 }, |
1961 |
|
{"getYear", date_getYear, 0,0,0 }, |
1962 |
|
{"getFullYear", date_getFullYear, 0,0,0 }, |
1963 |
|
{"getUTCFullYear", date_getUTCFullYear, 0,0,0 }, |
1964 |
|
{"getMonth", date_getMonth, 0,0,0 }, |
1965 |
|
{"getUTCMonth", date_getUTCMonth, 0,0,0 }, |
1966 |
|
{"getDate", date_getDate, 0,0,0 }, |
1967 |
|
{"getUTCDate", date_getUTCDate, 0,0,0 }, |
1968 |
|
{"getDay", date_getDay, 0,0,0 }, |
1969 |
|
{"getUTCDay", date_getUTCDay, 0,0,0 }, |
1970 |
|
{"getHours", date_getHours, 0,0,0 }, |
1971 |
|
{"getUTCHours", date_getUTCHours, 0,0,0 }, |
1972 |
|
{"getMinutes", date_getMinutes, 0,0,0 }, |
1973 |
|
{"getUTCMinutes", date_getUTCMinutes, 0,0,0 }, |
1974 |
|
{"getSeconds", date_getUTCSeconds, 0,0,0 }, |
1975 |
|
{"getUTCSeconds", date_getUTCSeconds, 0,0,0 }, |
1976 |
|
{"getMilliseconds", date_getUTCMilliseconds,0,0,0 }, |
1977 |
|
{"getUTCMilliseconds", date_getUTCMilliseconds,0,0,0 }, |
1978 |
|
{"setTime", date_setTime, 1,0,0 }, |
1979 |
|
{"setYear", date_setYear, 1,0,0 }, |
1980 |
|
{"setFullYear", date_setFullYear, 3,0,0 }, |
1981 |
|
{"setUTCFullYear", date_setUTCFullYear, 3,0,0 }, |
1982 |
|
{"setMonth", date_setMonth, 2,0,0 }, |
1983 |
|
{"setUTCMonth", date_setUTCMonth, 2,0,0 }, |
1984 |
|
{"setDate", date_setDate, 1,0,0 }, |
1985 |
|
{"setUTCDate", date_setUTCDate, 1,0,0 }, |
1986 |
|
{"setHours", date_setHours, 4,0,0 }, |
1987 |
|
{"setUTCHours", date_setUTCHours, 4,0,0 }, |
1988 |
|
{"setMinutes", date_setMinutes, 3,0,0 }, |
1989 |
|
{"setUTCMinutes", date_setUTCMinutes, 3,0,0 }, |
1990 |
|
{"setSeconds", date_setSeconds, 2,0,0 }, |
1991 |
|
{"setUTCSeconds", date_setUTCSeconds, 2,0,0 }, |
1992 |
|
{"setMilliseconds", date_setMilliseconds, 1,0,0 }, |
1993 |
|
{"setUTCMilliseconds", date_setUTCMilliseconds,1,0,0 }, |
1994 |
|
{"toUTCString", date_toGMTString, 0,0,0 }, |
1995 |
|
{js_toLocaleString_str, date_toLocaleString, 0,0,0 }, |
1996 |
|
{"toLocaleDateString", date_toLocaleDateString,0,0,0 }, |
1997 |
|
{"toLocaleTimeString", date_toLocaleTimeString,0,0,0 }, |
1998 |
|
{"toLocaleFormat", date_toLocaleFormat, 1,0,0 }, |
1999 |
|
{"toDateString", date_toDateString, 0,0,0 }, |
2000 |
|
{"toTimeString", date_toTimeString, 0,0,0 }, |
2001 |
|
#if JS_HAS_TOSOURCE |
2002 |
|
{js_toSource_str, date_toSource, 0,0,0 }, |
2003 |
|
#endif |
2004 |
|
{js_toString_str, date_toString, 0,0,0 }, |
2005 |
|
{js_valueOf_str, date_valueOf, 0,0,0 }, |
2006 |
|
{0,0,0,0,0} |
2007 |
|
}; |
2008 |
|
|
2009 |
|
static jsdouble * |
2010 |
|
date_constructor(JSContext *cx, JSObject* obj) |
2011 |
16 |
{ |
2012 |
16 |
jsdouble *date; |
2013 |
|
|
2014 |
16 |
date = js_NewDouble(cx, 0.0, 0); |
2015 |
16 |
if (!date) |
2016 |
0 |
return NULL; |
2017 |
16 |
OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, DOUBLE_TO_JSVAL(date)); |
2018 |
16 |
return date; |
2019 |
|
} |
2020 |
|
|
2021 |
|
static JSBool |
2022 |
|
Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
2023 |
0 |
{ |
2024 |
0 |
jsdouble *date; |
2025 |
0 |
JSString *str; |
2026 |
0 |
jsdouble d; |
2027 |
|
|
2028 |
|
/* Date called as function. */ |
2029 |
0 |
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { |
2030 |
0 |
int64 us, ms, us2ms; |
2031 |
0 |
jsdouble msec_time; |
2032 |
|
|
2033 |
|
/* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS', |
2034 |
|
* so compute ms from PRMJ_Now. |
2035 |
|
*/ |
2036 |
0 |
us = PRMJ_Now(); |
2037 |
0 |
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC); |
2038 |
0 |
JSLL_DIV(ms, us, us2ms); |
2039 |
0 |
JSLL_L2D(msec_time, ms); |
2040 |
|
|
2041 |
0 |
return date_format(cx, msec_time, FORMATSPEC_FULL, rval); |
2042 |
|
} |
2043 |
|
|
2044 |
|
/* Date called as constructor. */ |
2045 |
0 |
if (argc == 0) { |
2046 |
0 |
int64 us, ms, us2ms; |
2047 |
0 |
jsdouble msec_time; |
2048 |
|
|
2049 |
0 |
date = date_constructor(cx, obj); |
2050 |
0 |
if (!date) |
2051 |
0 |
return JS_FALSE; |
2052 |
|
|
2053 |
0 |
us = PRMJ_Now(); |
2054 |
0 |
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC); |
2055 |
0 |
JSLL_DIV(ms, us, us2ms); |
2056 |
0 |
JSLL_L2D(msec_time, ms); |
2057 |
|
|
2058 |
0 |
*date = msec_time; |
2059 |
0 |
} else if (argc == 1) { |
2060 |
0 |
if (!JSVAL_IS_STRING(argv[0])) { |
2061 |
|
/* the argument is a millisecond number */ |
2062 |
0 |
if (!js_ValueToNumber(cx, argv[0], &d)) |
2063 |
0 |
return JS_FALSE; |
2064 |
0 |
date = date_constructor(cx, obj); |
2065 |
0 |
if (!date) |
2066 |
0 |
return JS_FALSE; |
2067 |
0 |
*date = TIMECLIP(d); |
2068 |
|
} else { |
2069 |
|
/* the argument is a string; parse it. */ |
2070 |
0 |
date = date_constructor(cx, obj); |
2071 |
0 |
if (!date) |
2072 |
0 |
return JS_FALSE; |
2073 |
|
|
2074 |
0 |
str = js_ValueToString(cx, argv[0]); |
2075 |
0 |
if (!str) |
2076 |
0 |
return JS_FALSE; |
2077 |
|
|
2078 |
0 |
if (!date_parseString(str, date)) |
2079 |
0 |
*date = *cx->runtime->jsNaN; |
2080 |
0 |
*date = TIMECLIP(*date); |
2081 |
|
} |
2082 |
|
} else { |
2083 |
0 |
jsdouble array[MAXARGS]; |
2084 |
0 |
uintN loop; |
2085 |
0 |
jsdouble double_arg; |
2086 |
0 |
jsdouble day; |
2087 |
0 |
jsdouble msec_time; |
2088 |
|
|
2089 |
0 |
for (loop = 0; loop < MAXARGS; loop++) { |
2090 |
0 |
if (loop < argc) { |
2091 |
0 |
if (!js_ValueToNumber(cx, argv[loop], &double_arg)) |
2092 |
0 |
return JS_FALSE; |
2093 |
|
/* if any arg is NaN, make a NaN date object |
2094 |
|
and return */ |
2095 |
0 |
if (!JSDOUBLE_IS_FINITE(double_arg)) { |
2096 |
0 |
date = date_constructor(cx, obj); |
2097 |
0 |
if (!date) |
2098 |
0 |
return JS_FALSE; |
2099 |
0 |
*date = *cx->runtime->jsNaN; |
2100 |
0 |
return JS_TRUE; |
2101 |
|
} |
2102 |
0 |
array[loop] = js_DoubleToInteger(double_arg); |
2103 |
|
} else { |
2104 |
0 |
if (loop == 2) { |
2105 |
0 |
array[loop] = 1; /* Default the date argument to 1. */ |
2106 |
|
} else { |
2107 |
0 |
array[loop] = 0; |
2108 |
|
} |
2109 |
|
} |
2110 |
|
} |
2111 |
|
|
2112 |
0 |
date = date_constructor(cx, obj); |
2113 |
0 |
if (!date) |
2114 |
0 |
return JS_FALSE; |
2115 |
|
|
2116 |
|
/* adjust 2-digit years into the 20th century */ |
2117 |
0 |
if (array[0] >= 0 && array[0] <= 99) |
2118 |
0 |
array[0] += 1900; |
2119 |
|
|
2120 |
0 |
day = MakeDay(array[0], array[1], array[2]); |
2121 |
0 |
msec_time = MakeTime(array[3], array[4], array[5], array[6]); |
2122 |
0 |
msec_time = MakeDate(day, msec_time); |
2123 |
0 |
msec_time = UTC(msec_time); |
2124 |
0 |
*date = TIMECLIP(msec_time); |
2125 |
|
} |
2126 |
0 |
return JS_TRUE; |
2127 |
|
} |
2128 |
|
|
2129 |
|
JSObject * |
2130 |
|
js_InitDateClass(JSContext *cx, JSObject *obj) |
2131 |
16 |
{ |
2132 |
16 |
JSObject *proto; |
2133 |
16 |
jsdouble *proto_date; |
2134 |
|
|
2135 |
|
/* set static LocalTZA */ |
2136 |
16 |
LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond); |
2137 |
16 |
proto = JS_InitClass(cx, obj, NULL, &date_class, Date, MAXARGS, |
2138 |
|
NULL, date_methods, NULL, date_static_methods); |
2139 |
16 |
if (!proto) |
2140 |
0 |
return NULL; |
2141 |
|
|
2142 |
|
/* Alias toUTCString with toGMTString. (ECMA B.2.6) */ |
2143 |
16 |
if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString")) |
2144 |
0 |
return NULL; |
2145 |
|
|
2146 |
|
/* Set the value of the Date.prototype date to NaN */ |
2147 |
16 |
proto_date = date_constructor(cx, proto); |
2148 |
16 |
if (!proto_date) |
2149 |
0 |
return NULL; |
2150 |
16 |
*proto_date = *cx->runtime->jsNaN; |
2151 |
|
|
2152 |
16 |
return proto; |
2153 |
|
} |
2154 |
|
|
2155 |
|
JS_FRIEND_API(JSObject *) |
2156 |
|
js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time) |
2157 |
0 |
{ |
2158 |
0 |
JSObject *obj; |
2159 |
0 |
jsdouble *date; |
2160 |
|
|
2161 |
0 |
obj = js_NewObject(cx, &date_class, NULL, NULL); |
2162 |
0 |
if (!obj) |
2163 |
0 |
return NULL; |
2164 |
|
|
2165 |
0 |
date = date_constructor(cx, obj); |
2166 |
0 |
if (!date) |
2167 |
0 |
return NULL; |
2168 |
|
|
2169 |
0 |
*date = msec_time; |
2170 |
0 |
return obj; |
2171 |
|
} |
2172 |
|
|
2173 |
|
JS_FRIEND_API(JSObject *) |
2174 |
|
js_NewDateObject(JSContext* cx, int year, int mon, int mday, |
2175 |
|
int hour, int min, int sec) |
2176 |
0 |
{ |
2177 |
0 |
JSObject *obj; |
2178 |
0 |
jsdouble msec_time; |
2179 |
|
|
2180 |
0 |
msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); |
2181 |
0 |
obj = js_NewDateObjectMsec(cx, UTC(msec_time)); |
2182 |
0 |
return obj; |
2183 |
|
} |
2184 |
|
|
2185 |
|
JS_FRIEND_API(JSBool) |
2186 |
|
js_DateIsValid(JSContext *cx, JSObject* obj) |
2187 |
0 |
{ |
2188 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2189 |
|
|
2190 |
0 |
if (!date || JSDOUBLE_IS_NaN(*date)) |
2191 |
0 |
return JS_FALSE; |
2192 |
|
else |
2193 |
0 |
return JS_TRUE; |
2194 |
|
} |
2195 |
|
|
2196 |
|
JS_FRIEND_API(int) |
2197 |
|
js_DateGetYear(JSContext *cx, JSObject* obj) |
2198 |
0 |
{ |
2199 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2200 |
|
|
2201 |
|
/* Preserve legacy API behavior of returning 0 for invalid dates. */ |
2202 |
0 |
if (!date || JSDOUBLE_IS_NaN(*date)) |
2203 |
0 |
return 0; |
2204 |
0 |
return (int) YearFromTime(LocalTime(*date)); |
2205 |
|
} |
2206 |
|
|
2207 |
|
JS_FRIEND_API(int) |
2208 |
|
js_DateGetMonth(JSContext *cx, JSObject* obj) |
2209 |
0 |
{ |
2210 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2211 |
|
|
2212 |
0 |
if (!date || JSDOUBLE_IS_NaN(*date)) |
2213 |
0 |
return 0; |
2214 |
0 |
return (int) MonthFromTime(LocalTime(*date)); |
2215 |
|
} |
2216 |
|
|
2217 |
|
JS_FRIEND_API(int) |
2218 |
|
js_DateGetDate(JSContext *cx, JSObject* obj) |
2219 |
0 |
{ |
2220 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2221 |
|
|
2222 |
0 |
if (!date || JSDOUBLE_IS_NaN(*date)) |
2223 |
0 |
return 0; |
2224 |
0 |
return (int) DateFromTime(LocalTime(*date)); |
2225 |
|
} |
2226 |
|
|
2227 |
|
JS_FRIEND_API(int) |
2228 |
|
js_DateGetHours(JSContext *cx, JSObject* obj) |
2229 |
0 |
{ |
2230 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2231 |
|
|
2232 |
0 |
if (!date || JSDOUBLE_IS_NaN(*date)) |
2233 |
0 |
return 0; |
2234 |
0 |
return (int) HourFromTime(LocalTime(*date)); |
2235 |
|
} |
2236 |
|
|
2237 |
|
JS_FRIEND_API(int) |
2238 |
|
js_DateGetMinutes(JSContext *cx, JSObject* obj) |
2239 |
0 |
{ |
2240 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2241 |
|
|
2242 |
0 |
if (!date || JSDOUBLE_IS_NaN(*date)) |
2243 |
0 |
return 0; |
2244 |
0 |
return (int) MinFromTime(LocalTime(*date)); |
2245 |
|
} |
2246 |
|
|
2247 |
|
JS_FRIEND_API(int) |
2248 |
|
js_DateGetSeconds(JSContext *cx, JSObject* obj) |
2249 |
0 |
{ |
2250 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2251 |
|
|
2252 |
0 |
if (!date || JSDOUBLE_IS_NaN(*date)) |
2253 |
0 |
return 0; |
2254 |
0 |
return (int) SecFromTime(*date); |
2255 |
|
} |
2256 |
|
|
2257 |
|
JS_FRIEND_API(void) |
2258 |
|
js_DateSetYear(JSContext *cx, JSObject *obj, int year) |
2259 |
0 |
{ |
2260 |
0 |
jsdouble local; |
2261 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2262 |
0 |
if (!date) |
2263 |
0 |
return; |
2264 |
0 |
local = LocalTime(*date); |
2265 |
|
/* reset date if it was NaN */ |
2266 |
0 |
if (JSDOUBLE_IS_NaN(local)) |
2267 |
0 |
local = 0; |
2268 |
0 |
local = date_msecFromDate(year, |
2269 |
|
MonthFromTime(local), |
2270 |
|
DateFromTime(local), |
2271 |
|
HourFromTime(local), |
2272 |
|
MinFromTime(local), |
2273 |
|
SecFromTime(local), |
2274 |
|
msFromTime(local)); |
2275 |
0 |
*date = UTC(local); |
2276 |
|
} |
2277 |
|
|
2278 |
|
JS_FRIEND_API(void) |
2279 |
|
js_DateSetMonth(JSContext *cx, JSObject *obj, int month) |
2280 |
0 |
{ |
2281 |
0 |
jsdouble local; |
2282 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2283 |
0 |
if (!date) |
2284 |
0 |
return; |
2285 |
0 |
local = LocalTime(*date); |
2286 |
|
/* bail if date was NaN */ |
2287 |
0 |
if (JSDOUBLE_IS_NaN(local)) |
2288 |
0 |
return; |
2289 |
0 |
local = date_msecFromDate(YearFromTime(local), |
2290 |
|
month, |
2291 |
|
DateFromTime(local), |
2292 |
|
HourFromTime(local), |
2293 |
|
MinFromTime(local), |
2294 |
|
SecFromTime(local), |
2295 |
|
msFromTime(local)); |
2296 |
0 |
*date = UTC(local); |
2297 |
|
} |
2298 |
|
|
2299 |
|
JS_FRIEND_API(void) |
2300 |
|
js_DateSetDate(JSContext *cx, JSObject *obj, int date) |
2301 |
0 |
{ |
2302 |
0 |
jsdouble local; |
2303 |
0 |
jsdouble *datep = date_getProlog(cx, obj, NULL); |
2304 |
0 |
if (!datep) |
2305 |
0 |
return; |
2306 |
0 |
local = LocalTime(*datep); |
2307 |
0 |
if (JSDOUBLE_IS_NaN(local)) |
2308 |
0 |
return; |
2309 |
0 |
local = date_msecFromDate(YearFromTime(local), |
2310 |
|
MonthFromTime(local), |
2311 |
|
date, |
2312 |
|
HourFromTime(local), |
2313 |
|
MinFromTime(local), |
2314 |
|
SecFromTime(local), |
2315 |
|
msFromTime(local)); |
2316 |
0 |
*datep = UTC(local); |
2317 |
|
} |
2318 |
|
|
2319 |
|
JS_FRIEND_API(void) |
2320 |
|
js_DateSetHours(JSContext *cx, JSObject *obj, int hours) |
2321 |
0 |
{ |
2322 |
0 |
jsdouble local; |
2323 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2324 |
0 |
if (!date) |
2325 |
0 |
return; |
2326 |
0 |
local = LocalTime(*date); |
2327 |
0 |
if (JSDOUBLE_IS_NaN(local)) |
2328 |
0 |
return; |
2329 |
0 |
local = date_msecFromDate(YearFromTime(local), |
2330 |
|
MonthFromTime(local), |
2331 |
|
DateFromTime(local), |
2332 |
|
hours, |
2333 |
|
MinFromTime(local), |
2334 |
|
SecFromTime(local), |
2335 |
|
msFromTime(local)); |
2336 |
0 |
*date = UTC(local); |
2337 |
|
} |
2338 |
|
|
2339 |
|
JS_FRIEND_API(void) |
2340 |
|
js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes) |
2341 |
0 |
{ |
2342 |
0 |
jsdouble local; |
2343 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2344 |
0 |
if (!date) |
2345 |
0 |
return; |
2346 |
0 |
local = LocalTime(*date); |
2347 |
0 |
if (JSDOUBLE_IS_NaN(local)) |
2348 |
0 |
return; |
2349 |
0 |
local = date_msecFromDate(YearFromTime(local), |
2350 |
|
MonthFromTime(local), |
2351 |
|
DateFromTime(local), |
2352 |
|
HourFromTime(local), |
2353 |
|
minutes, |
2354 |
|
SecFromTime(local), |
2355 |
|
msFromTime(local)); |
2356 |
0 |
*date = UTC(local); |
2357 |
|
} |
2358 |
|
|
2359 |
|
JS_FRIEND_API(void) |
2360 |
|
js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds) |
2361 |
0 |
{ |
2362 |
0 |
jsdouble local; |
2363 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2364 |
0 |
if (!date) |
2365 |
0 |
return; |
2366 |
0 |
local = LocalTime(*date); |
2367 |
0 |
if (JSDOUBLE_IS_NaN(local)) |
2368 |
0 |
return; |
2369 |
0 |
local = date_msecFromDate(YearFromTime(local), |
2370 |
|
MonthFromTime(local), |
2371 |
|
DateFromTime(local), |
2372 |
|
HourFromTime(local), |
2373 |
|
MinFromTime(local), |
2374 |
|
seconds, |
2375 |
|
msFromTime(local)); |
2376 |
0 |
*date = UTC(local); |
2377 |
|
} |
2378 |
|
|
2379 |
|
JS_FRIEND_API(jsdouble) |
2380 |
|
js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj) |
2381 |
0 |
{ |
2382 |
0 |
jsdouble *date = date_getProlog(cx, obj, NULL); |
2383 |
0 |
if (!date || JSDOUBLE_IS_NaN(*date)) |
2384 |
0 |
return 0; |
2385 |
0 |
return (*date); |