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