~ubuntu-branches/debian/wheezy/couchdb/wheezy

« back to all changes in this revision

Viewing changes to src/js/jsdate.c

  • Committer: Bazaar Package Importer
  • Author(s): Noah Slater
  • Date: 2008-02-06 17:03:38 UTC
  • Revision ID: james.westby@ubuntu.com-20080206170338-y411anylx3oplqid
Tags: upstream-0.7.3~svn684
ImportĀ upstreamĀ versionĀ 0.7.3~svn684

Show diffs side-by-side

added added

removed removed

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