home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- /*
- * JS date methods.
- */
- #include <math.h>
- #include <stdlib.h>
- #include <string.h>
- #include "prtypes.h"
- #include "prprf.h"
- #include "prmjtime.h"
- #include "prlog.h"
- #include "jsapi.h"
- #include "jsconfig.h"
- #include "jscntxt.h"
- #include "jsdate.h"
- #include "jslock.h"
- #include "jsnum.h"
- #include "jsobj.h"
- #include "jsstr.h"
-
- #include <stdio.h>
-
- /*
- * The JS 'Date' object is patterned after the Java 'Date' object.
- * Here is an script:
- *
- * today = new Date();
- *
- * print(today.toLocaleString());
- *
- * weekDay = today.getDay();
- *
- *
- * These Java (and ECMA-262) methods are supported:
- *
- * UTC
- * getDate (getUTCDate)
- * getDay (getUTCDay)
- * getHours (getUTCHours)
- * getMinutes (getUTCMinutes)
- * getMonth (getUTCMonth)
- * getSeconds (getUTCSeconds)
- * getMilliseconds (getUTCMilliseconds)
- * getTime
- * getTimezoneOffset
- * getYear
- * getFullYear (getUTCFullYear)
- * parse
- * setDate (setUTCDate)
- * setHours (setUTCHours)
- * setMinutes (setUTCMinutes)
- * setMonth (setUTCMonth)
- * setSeconds (setUTCSeconds)
- * setMilliseconds (setUTCMilliseconds)
- * setTime
- * setYear (setFullYear, setUTCFullYear)
- * toGMTString (toUTCString)
- * toLocaleString
- * toString
- *
- *
- * These Java methods are not supported
- *
- * setDay
- * before
- * after
- * equals
- * hashCode
- */
-
- /*
- * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262
- * language definition and reduce dependence on NSPR. NSPR is used to
- * get the current time in milliseconds, the time zone offset, and the
- * daylight savings time offset for a given time. NSPR is also used
- * for Date.toLocaleString() (only), for locale-specific formatting.
-
- * To do:
- * (I did some performance tests by timing how long it took to run what
- * I had of the js ECMA conformance tests.)
- *
- * - look at saving results across multiple calls to supporting
- * functions; the toString functions compute some of the same values
- * multiple times. Although - I took a quick stab at this, and I lost
- * rather than gained. (Fractionally.) Hard to tell what compilers/processors
- * are doing these days.
- * - look at tweaking function return types to return double instead
- * of int; this seems to make things run slightly faster sometimes.
- * (though it could be architecture-dependent.) It'd be good to see
- * how this does on win32. (Tried it on irix.) Types could use a
- * general going-over.
- */
-
- /*
- * Supporting functions - ECMA 15.9.1.*
- */
-
- #define HalfTimeDomain 8.64e15
- #define HoursPerDay 24.0
- #define MinutesPerDay (HoursPerDay * MinutesPerHour)
- #define MinutesPerHour 60.0
- #define SecondsPerDay (MinutesPerDay * SecondsPerMinute)
- #define SecondsPerHour (MinutesPerHour * SecondsPerMinute)
- #define SecondsPerMinute 60.0
- #define msPerDay (SecondsPerDay * msPerSecond)
- #define msPerHour (SecondsPerHour * msPerSecond)
- #define msPerMinute (SecondsPerMinute * msPerSecond)
- #define msPerSecond 1000.0
-
- #define Day(t) floor((t) / msPerDay)
-
- static jsdouble
- TimeWithinDay(jsdouble t)
- {
- jsdouble result;
- result = fmod(t, msPerDay);
- if (result < 0)
- result += msPerDay;
- return result;
- }
-
- #define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \
- ? 366 : 365)
-
- /* math here has to be f.p, because we need
- * floor((1968 - 1969) / 4) == -1
- */
- #define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \
- - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
- #define TimeFromYear(y) (DayFromYear(y) * msPerDay)
-
- static jsint
- YearFromTime(jsdouble t)
- {
- jsint lo = (jsint) floor((t / msPerDay) / 366) + 1970;
- jsint hi = (jsint) floor((t / msPerDay) / 365) + 1970;
- jsint mid;
-
- /* above doesn't work for negative dates... */
- if (hi < lo) {
- jsint temp = lo;
- lo = hi;
- hi = temp;
- }
-
- /* Use a simple binary search algorithm to find the right
- year. This seems like brute force... but the computation
- of hi and lo years above lands within one year of the
- correct answer for years within a thousand years of
- 1970; the loop below only requires six iterations
- for year 270000. */
- while (hi > lo) {
- mid = (hi + lo) / 2;
- if (TimeFromYear(mid) > t) {
- hi = mid - 1;
- } else {
- if (TimeFromYear(mid) <= t) {
- jsint temp = mid + 1;
- if (TimeFromYear(temp) > t) {
- return mid;
- }
- lo = mid + 1;
- }
- }
- }
- return lo;
- }
-
- #define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366)
-
- #define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
-
- /*
- * The following array contains the day of year for the first day of
- * each month, where index 0 is January, and day 0 is January 1.
- */
- static jsdouble firstDayOfMonth[2][12] = {
- {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0},
- {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0}
- };
-
- #define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m];
-
- static intN
- MonthFromTime(jsdouble t)
- {
- intN d, step;
- jsint year = YearFromTime(t);
- d = DayWithinYear(t, year);
-
- if (d < (step = 31))
- return 0;
- step += (InLeapYear(t) ? 29 : 28);
- if (d < step)
- return 1;
- if (d < (step += 31))
- return 2;
- if (d < (step += 30))
- return 3;
- if (d < (step += 31))
- return 4;
- if (d < (step += 30))
- return 5;
- if (d < (step += 31))
- return 6;
- if (d < (step += 31))
- return 7;
- if (d < (step += 30))
- return 8;
- if (d < (step += 31))
- return 9;
- if (d < (step += 30))
- return 10;
- return 11;
- }
-
- static intN
- DateFromTime(jsdouble t)
- {
- intN d, step, next;
- jsint year = YearFromTime(t);
- d = DayWithinYear(t, year);
-
- if (d <= (next = 30))
- return d + 1;
- step = next;
- next += (InLeapYear(t) ? 29 : 28);
- if (d <= next)
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 30))
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 30))
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 30))
- return d - step;
- step = next;
- if (d <= (next += 31))
- return d - step;
- step = next;
- if (d <= (next += 30))
- return d - step;
- step = next;
- return d - step;
- }
-
- static intN
- WeekDay(jsdouble t)
- {
- jsint result;
- result = (jsint) Day(t) + 4;
- result = result % 7;
- if (result < 0)
- result += 7;
- return (intN) result;
- }
-
- /* LocalTZA gets set by js_InitDateClass() */
- static jsdouble LocalTZA;
-
- static jsdouble
- DaylightSavingTA(jsdouble t)
- {
- int64 PR_t;
- int64 ms2us;
- int64 offset;
- jsdouble result;
-
- /* abort if NaN */
- if (t != t)
- return t;
-
- /* put our t in an LL, and map it to usec for prtime */
- LL_D2L(PR_t, t);
- LL_I2L(ms2us, PRMJ_USEC_PER_MSEC);
- LL_MUL(PR_t, PR_t, ms2us);
-
- offset = PRMJ_DSTOffset(PR_t);
-
- LL_DIV(offset, offset, ms2us);
- LL_L2D(result, offset);
- return result;
- }
-
- #define LocalTime(t) ((t) + LocalTZA + DaylightSavingTA(t))
- /* #define UTC(t) ((t) - LocalTZA - DaylightSavingTA((t) - LocalTZA)) */
- static jsdouble
- UTC(jsdouble t)
- {
- /* fprintf(stderr, "time %f\n", t); */
- /* fprintf(stderr, "LocalTZA %f\n", LocalTZA); */
- /* fprintf(stderr, "DaylightSavingTA %f\n", DaylightSavingTA(t - LocalTZA)); */
-
- return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
- }
-
- static intN
- HourFromTime(jsdouble t)
- {
- intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
- if (result < 0)
- result += (intN)HoursPerDay;
- return result;
- }
-
- static intN
- MinFromTime(jsdouble t)
- {
- intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
- if (result < 0)
- result += (intN)MinutesPerHour;
- return result;
- }
-
- static intN
- SecFromTime(jsdouble t)
- {
- intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute);
- if (result < 0)
- result += (intN)SecondsPerMinute;
- return result;
- }
-
- static intN
- msFromTime(jsdouble t)
- {
- intN result = (intN) fmod(t, msPerSecond);
- if (result < 0)
- result += (intN)msPerSecond;
- return result;
- }
-
- #define MakeTime(hour, min, sec, ms) \
- (((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms)
-
- static jsdouble
- MakeDay(jsdouble year, jsdouble month, jsdouble date)
- {
- jsdouble result;
- JSBool leap;
- jsdouble yearday;
- jsdouble monthday;
-
- year += floor(month / 12);
-
- month = fmod(month, 12);
- if (month < 0)
- month += 12;
-
- leap = (DaysInYear((jsint) year) == 366);
-
- yearday = floor(TimeFromYear(year) / msPerDay);
- monthday = DayFromMonth(month, leap);
-
- result = yearday
- + monthday
- + date - 1;
- return result;
- }
-
- #define MakeDate(day, time) (day * msPerDay + time)
-
- #define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
- && !((d < 0 ? -d : d) > HalfTimeDomain)) \
- ? js_DoubleToInteger(d + (+0.)) : *(cx->runtime->jsNaN))
-
- /**
- * end of ECMA 'support' functions
- */
-
- /*
- * Other Support routines and definitions
- */
-
- static JSClass date_class = {
- "Date",
- JSCLASS_HAS_PRIVATE,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
- };
-
- /* for use by date_parse */
-
- static char* wtb[] = {
- "am", "pm",
- "monday", "tuesday", "wednesday", "thursday", "friday",
- "saturday", "sunday",
- "january", "february", "march", "april", "may", "june",
- "july", "august", "september", "october", "november", "december",
- "gmt", "ut", "utc",
- "est", "edt",
- "cst", "cdt",
- "mst", "mdt",
- "pst", "pdt"
- /* time zone table needs to be expanded */
- };
-
- static int ttb[] = {
- 0, 1, 0, 0, 0, 0, 0, 0, 0,
- 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
- 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
- 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
- 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
- 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
- 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
- };
-
- /* helper for date_parse */
- static JSBool
- date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
- int count, int ignoreCase)
- {
- JSBool result = JS_FALSE;
- /* return true if matches, otherwise, false */
-
- while (count > 0 && s1[s1off] && s2[s2off]) {
- if (ignoreCase) {
- if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) {
- break;
- }
- } else {
- if ((jschar)s1[s1off] != s2[s2off]) {
- break;
- }
- }
- s1off++;
- s2off++;
- count--;
- }
-
- if (count == 0) {
- result = JS_TRUE;
- }
-
- return result;
- }
-
- /* find UTC time from given date... no 1900 correction! */
- static jsdouble
- date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour,
- jsdouble min, jsdouble sec, jsdouble msec)
- {
- jsdouble day;
- jsdouble time;
- jsdouble result;
-
- day = MakeDay(year, mon, mday);
- time = MakeTime(hour, min, sec, msec);
- result = MakeDate(day, time);
- return result;
- }
-
- /*
- * See ECMA 15.9.4.[3-10];
- */
- /* XXX this function must be above date_parseString to avoid a
- horrid bug in the Win16 1.52 compiler */
- #define MAXARGS 7
- static JSBool
- date_UTC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- jsdouble array[MAXARGS];
- uintN loop;
- jsdouble d;
-
- for (loop = 0; loop < MAXARGS; loop++) {
- if (loop < argc) {
- if (!JS_ValueToNumber(cx, argv[loop], &d))
- return JS_FALSE;
- /* return NaN if any arg is NaN */
- if (!JSDOUBLE_IS_FINITE(d)) {
- return js_NewNumberValue(cx, d, rval);
- }
- array[loop] = floor(d);
- } else {
- array[loop] = 0;
- }
- }
-
- /* adjust 2-digit years into the 20th century */
- if (array[0] >= 0 && array[0] <= 99)
- array[0] += 1900;
-
- /* if we got a 0 for 'date' (which is out of range)
- * pretend it's a 1. (So Date.UTC(1972, 5) works) */
- if (array[2] < 1)
- array[2] = 1;
-
- d = date_msecFromDate(array[0], array[1], array[2],
- array[3], array[4], array[5], array[6]);
- d = TIMECLIP(d);
-
- return js_NewNumberValue(cx, d, rval);
- }
-
- static JSBool
- date_parseString(const jschar *s, jsdouble *result)
- {
- jsdouble msec;
-
- int year = -1;
- int mon = -1;
- int mday = -1;
- int hour = -1;
- int min = -1;
- int sec = -1;
- int c = -1;
- int i = 0;
- int n = -1;
- jsdouble tzoffset = -1; /* was an int, overflowed on win16!!! */
- int prevc = 0;
- int limit = 0;
- JSBool seenplusminus = JS_FALSE;
-
- if (s == 0)
- goto syntax;
- limit = js_strlen(s);
- while (i < limit) {
- c = s[i];
- i++;
- if (c <= ' ' || c == ',' || c == '-') {
- if (c == '-' && '0' <= s[i] && s[i] <= '9') {
- prevc = c;
- }
- continue;
- }
- if (c == '(') { /* comments) */
- int depth = 1;
- while (i < limit) {
- c = s[i];
- i++;
- if (c == '(') depth++;
- else if (c == ')')
- if (--depth <= 0)
- break;
- }
- continue;
- }
- if ('0' <= c && c <= '9') {
- n = c - '0';
- while (i < limit && '0' <= (c = s[i]) && c <= '9') {
- n = n * 10 + c - '0';
- i++;
- }
-
- /* allow TZA before the year, so
- * 'Wed Nov 05 21:49:11 GMT-0800 1997'
- * works */
-
- /* uses of seenplusminus allow : in TZA, so Java
- * no-timezone style of GMT+4:30 works
- */
-
- if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
- /* make ':' case below change tzoffset */
- seenplusminus = JS_TRUE;
-
- /* offset */
- if (n < 24)
- n = n * 60; /* EG. "GMT-3" */
- else
- n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
- if (prevc == '+') /* plus means east of GMT */
- n = -n;
- if (tzoffset != 0 && tzoffset != -1)
- goto syntax;
- tzoffset = n;
- } else if (n >= 70 ||
- (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
- if (year >= 0)
- goto syntax;
- else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
- year = n < 100 ? n + 1900 : n;
- else
- goto syntax;
- } else if (c == ':') {
- if (hour < 0)
- hour = /*byte*/ n;
- else if (min < 0)
- min = /*byte*/ n;
- else
- goto syntax;
- } else if (c == '/') {
- if (mon < 0)
- mon = /*byte*/ n-1;
- else if (mday < 0)
- mday = /*byte*/ n;
- else
- goto syntax;
- } else if (i < limit && c != ',' && c > ' ' && c != '-') {
- goto syntax;
- } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
- if (tzoffset < 0)
- tzoffset -= n;
- else
- tzoffset += n;
- } else if (hour >= 0 && min < 0) {
- min = /*byte*/ n;
- } else if (min >= 0 && sec < 0) {
- sec = /*byte*/ n;
- } else if (mday < 0) {
- mday = /*byte*/ n;
- } else {
- goto syntax;
- }
- prevc = 0;
- } else if (c == '/' || c == ':' || c == '+' || c == '-') {
- prevc = c;
- } else {
- int st = i - 1;
- int k;
- while (i < limit) {
- c = s[i];
- if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
- break;
- i++;
- }
- if (i <= st + 1)
- goto syntax;
- for (k = (sizeof(wtb)/sizeof(char*)); --k >= 0;)
- if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
- int action = ttb[k];
- if (action != 0)
- if (action == 1) /* pm */
- if (hour > 12 || hour < 0)
- goto syntax;
- else
- hour += 12;
- else if (action <= 13) /* month! */
- if (mon < 0)
- mon = /*byte*/ (action - 2);
- else
- goto syntax;
- else
- tzoffset = action - 10000;
- break;
- }
- if (k < 0)
- goto syntax;
- prevc = 0;
- }
- }
- if (year < 0 || mon < 0 || mday < 0)
- goto syntax;
- if (sec < 0)
- sec = 0;
- if (min < 0)
- min = 0;
- if (hour < 0)
- hour = 0;
- if (tzoffset == -1) { /* no time zone specified, have to use local */
- jsdouble time;
- time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
-
- *result = UTC(time);
- return JS_TRUE;
- }
-
- msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
- msec += tzoffset * msPerMinute;
- *result = msec;
- return JS_TRUE;
-
- syntax:
- /* syntax error */
- *result = 0;
- return JS_FALSE;
- }
-
- static JSBool
- date_parse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSString *str;
- jsdouble result;
-
- str = JS_ValueToString(cx, argv[0]);
- if (!str)
- return JS_FALSE;
- if (!date_parseString(str->chars, &result)) {
- *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
- return JS_TRUE;
- }
-
- result = TIMECLIP(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- /*
- * Check that obj is an object of class Date,
- * and get the date value. Return NULL on failure,
- * which should be out of band, because the value
- * not publicly accessable.
- */
- static jsdouble *
- date_getProlog(JSContext *cx, JSObject *obj, jsval *argv) {
- jsdouble *result;
- if (!JS_InstanceOf(cx, obj, &date_class, argv)) {
- return NULL;
- }
- JS_LOCK(cx);
- result = JSVAL_TO_DOUBLE(OBJ_GET_SLOT(obj, JSSLOT_PRIVATE));
- JS_UNLOCK(cx);
- return result;
- }
-
- /*
- * See ECMA 15.9.5.4 thru 15.9.5.23
- */
- static JSBool
- date_getTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
-
- return js_NewNumberValue(cx, *date, rval);
- }
-
- static JSBool
- date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = YearFromTime(LocalTime(result));
- result -= 1900;
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = YearFromTime(LocalTime(result));
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = YearFromTime(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = MonthFromTime(LocalTime(result));
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getUTCMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = MonthFromTime(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = LocalTime(result);
- result = DateFromTime(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getUTCDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = DateFromTime(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = LocalTime(result);
- result = WeekDay(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getUTCDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = WeekDay(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = HourFromTime(LocalTime(result));
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getUTCHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = HourFromTime(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = MinFromTime(LocalTime(result));
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = MinFromTime(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- /* Date.getSeconds is mapped to getUTCSeconds */
-
- static JSBool
- date_getUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = SecFromTime(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- /* Date.getMilliseconds is mapped to getUTCMilliseconds */
-
- static JSBool
- date_getUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- result = msFromTime(result);
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_getTimezoneOffset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- result = *date;
-
- /*
- * Return the time zone offset in minutes for the current locale
- * that is appropriate for this time. This value would be a
- * constant except for daylight savings time.
- */
- result = (result - LocalTime(result)) / msPerMinute;
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_setTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- jsdouble result;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
-
- if (!JS_ValueToNumber(cx, argv[0], &result))
- return JS_FALSE;
-
- *date = result;
- return js_NewNumberValue(cx, result, rval);
- }
-
- static JSBool
- date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- uintN maxargs, JSBool local, jsval *rval)
- {
- uintN i;
- jsdouble args[4], *argp, *stop;
- jsdouble hour, min, sec, msec;
- jsdouble lorutime; /* Local or UTC version of *date */
-
- jsdouble time;
- jsdouble result;
-
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
-
- result = *date;
-
- /* just return NaN if the date is already NaN */
- if (!JSDOUBLE_IS_FINITE(result))
- return js_NewNumberValue(cx, result, rval);
-
- for (i = 0; i < argc; i++) {
- if (!JS_ValueToNumber(cx, argv[i], &args[i]))
- return JS_FALSE;
- if (!JSDOUBLE_IS_FINITE(args[i])) {
- *date = *(cx->runtime->jsNaN);
- return js_NewNumberValue(cx, *date, rval);
- }
- args[i] = js_DoubleToInteger(args[i]);
- }
-
- if (local)
- lorutime = LocalTime(result);
- else
- lorutime = result;
-
- argp = args;
- stop = argp + argc;
- if (maxargs >= 4 && argp < stop)
- hour = *argp++;
- else
- hour = HourFromTime(lorutime);
-
- if (maxargs >= 3 && argp < stop)
- min = *argp++;
- else
- min = MinFromTime(lorutime);
-
- if (maxargs >= 2 && argp < stop)
- sec = *argp++;
- else
- sec = SecFromTime(lorutime);
-
- if (maxargs >= 1 && argp < stop)
- msec = *argp;
- else
- msec = msFromTime(lorutime);
-
- time = MakeTime(hour, min, sec, msec);
- result = MakeDate(Day(lorutime), time);
-
- /* fprintf(stderr, "%f\n", result); */
-
- if (local)
- result = UTC(result);
-
- /* fprintf(stderr, "%f\n", result); */
-
- *date = TIMECLIP(result);
- return js_NewNumberValue(cx, *date, rval);
- }
-
- static JSBool
- date_setMilliseconds(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeTime(cx, obj, argc, argv, 1, JS_TRUE, rval);
- }
-
- static JSBool
- date_setUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeTime(cx, obj, argc, argv, 1, JS_FALSE, rval);
- }
-
- static JSBool
- date_setSeconds(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeTime(cx, obj, argc, argv, 2, JS_TRUE, rval);
- }
-
- static JSBool
- date_setUTCSeconds(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeTime(cx, obj, argc, argv, 2, JS_FALSE, rval);
- }
-
- static JSBool
- date_setMinutes(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeTime(cx, obj, argc, argv, 3, JS_TRUE, rval);
- }
-
- static JSBool
- date_setUTCMinutes(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeTime(cx, obj, argc, argv, 3, JS_FALSE, rval);
- }
-
- static JSBool
- date_setHours(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeTime(cx, obj, argc, argv, 4, JS_TRUE, rval);
- }
-
- static JSBool
- date_setUTCHours(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeTime(cx, obj, argc, argv, 4, JS_FALSE, rval);
- }
-
- static JSBool
- date_makeDate(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, uintN maxargs, JSBool local, jsval *rval)
- {
- uintN i;
- jsdouble lorutime; /* local or UTC version of *date */
- jsdouble args[3], *argp, *stop;
- jsdouble year, month, day;
- jsdouble result;
-
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
-
- result = *date;
-
- for (i = 0; i < argc; i++) {
- if (!JS_ValueToNumber(cx, argv[i], &args[i]))
- return JS_FALSE;
- if (!JSDOUBLE_IS_FINITE(args[i])) {
- *date = *(cx->runtime->jsNaN);
- return js_NewNumberValue(cx, *date, rval);
- }
- args[i] = js_DoubleToInteger(args[i]);
- }
-
- /* return NaN if date is NaN and we're not setting the year,
- * If we are, use 0 as the time. */
- if (!(JSDOUBLE_IS_FINITE(result))) {
- if (argc < 3)
- return js_NewNumberValue(cx, result, rval);
- else
- lorutime = +0.;
- } else {
- if (local)
- lorutime = LocalTime(result);
- else
- lorutime = result;
- }
-
- argp = args;
- stop = argp + argc;
- if (maxargs >= 3 && argp < stop)
- year = *argp++;
- else
- year = YearFromTime(lorutime);
-
- if (maxargs >= 2 && argp < stop)
- month = *argp++;
- else
- month = MonthFromTime(lorutime);
-
- if (maxargs >= 1 && argp < stop)
- day = *argp++;
- else
- day = DateFromTime(lorutime);
-
- day = MakeDay(year, month, day); /* day within year */
- result = MakeDate(day, TimeWithinDay(lorutime));
-
- if (local)
- result = UTC(result);
-
- *date = TIMECLIP(result);
- return js_NewNumberValue(cx, *date, rval);
- }
-
- static JSBool
- date_setDate(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeDate(cx, obj, argc, argv, 1, JS_TRUE, rval);
- }
-
- static JSBool
- date_setUTCDate(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeDate(cx, obj, argc, argv, 1, JS_FALSE, rval);
- }
-
- static JSBool
- date_setMonth(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeDate(cx, obj, argc, argv, 2, JS_TRUE, rval);
- }
-
- static JSBool
- date_setUTCMonth(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeDate(cx, obj, argc, argv, 2, JS_FALSE, rval);
- }
-
- static JSBool
- date_setFullYear(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeDate(cx, obj, argc, argv, 3, JS_TRUE, rval);
- }
-
- static JSBool
- date_setUTCFullYear(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- return date_makeDate(cx, obj, argc, argv, 3, JS_FALSE, rval);
- }
-
- static JSBool
- date_setYear(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- jsdouble t;
- jsdouble year;
- jsdouble day;
- jsdouble result;
-
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
-
- result = *date;
-
- if (!JS_ValueToNumber(cx, argv[0], &year))
- return JS_FALSE;
- if (!JSDOUBLE_IS_FINITE(year)) {
- *date = *(cx->runtime->jsNaN);
- return js_NewNumberValue(cx, *date, rval);
- }
-
- year = js_DoubleToInteger(year);
-
- if (!JSDOUBLE_IS_FINITE(result)) {
- t = +0.0;
- } else {
- t = LocalTime(result);
- }
-
- if (year >= 0 && year <= 99)
- year += 1900;
-
- day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
- result = MakeDate(day, TimeWithinDay(t));
- result = UTC(result);
-
- *date = TIMECLIP(result);
- return js_NewNumberValue(cx, *date, rval);
- }
-
- /* constants for toString, toUTCString */
- static char js_NaN_date_str[] = "Invalid Date";
- static const char* days[] =
- {
- "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
- };
- static const char* months[] =
- {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- static JSBool
- date_toGMTString(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- char buf[100];
- JSString *str;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
-
- if (!JSDOUBLE_IS_FINITE(*date)) {
- PR_snprintf(buf, sizeof buf, js_NaN_date_str);
- } else {
- jsdouble temp = *date;
-
- /* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
- * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
- */
- PR_snprintf(buf, sizeof buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
- days[WeekDay(temp)],
- DateFromTime(temp),
- months[MonthFromTime(temp)],
- YearFromTime(temp),
- HourFromTime(temp),
- MinFromTime(temp),
- SecFromTime(temp));
- }
- str = JS_NewStringCopyZ(cx, buf);
- if (!str)
- return JS_FALSE;
- *rval = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- /* for Date.toLocaleString; interface to PRMJTime date struct. */
- static void
- new_explode(jsdouble time, PRMJTime *split)
- {
- jsint year = YearFromTime(time);
-
- split->tm_usec = (int32) msFromTime(time) * 1000;
- split->tm_sec = (int8) SecFromTime(time);
- split->tm_min = (int8) MinFromTime(time);
- split->tm_hour = (int8) HourFromTime(time);
- split->tm_mday = (int8) DateFromTime(time);
- split->tm_mon = (int8) MonthFromTime(time);
- split->tm_wday = (int8) WeekDay(time);
- split->tm_year = (int16) year;
- split->tm_yday = (int16) DayWithinYear(time, year);
-
- /* not sure how this affects things, but it doesn't seem
- to matter. */
- split->tm_isdst = (DaylightSavingTA(time) != 0);
- }
-
- static JSBool
- date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- char buf[100];
- JSString *str;
- PRMJTime split;
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
-
- if (!JSDOUBLE_IS_FINITE(*date)) {
- PR_snprintf(buf, sizeof buf, js_NaN_date_str);
- } else {
- jsdouble local = LocalTime(*date);
- new_explode(local, &split);
-
- /* let PRMJTime format it. */
- PRMJ_FormatTime(buf, sizeof buf, "%c", &split);
- }
-
- str = JS_NewStringCopyZ(cx, buf);
- if (!str)
- return JS_FALSE;
- *rval = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- /* helper function */
- static JSBool
- date_format(JSContext *cx, jsdouble date, jsval *rval)
- {
- char buf[100];
- JSString *str;
- char tzbuf[100];
- PRMJTime split;
-
- if (!JSDOUBLE_IS_FINITE(date)) {
- PR_snprintf(buf, sizeof buf, js_NaN_date_str);
- } else {
- jsdouble local = LocalTime(date);
-
- /* offset from GMT in minutes. The offset includes daylight savings,
- if it applies. */
- jsint minutes = (jsint) floor((LocalTZA + DaylightSavingTA(local))
- / msPerMinute);
-
- /* map 510 minutes to 0830 hours */
- intN offset = (minutes / 60) * 100 + minutes % 60;
-
- /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
- * printed as 'GMT-0800' rather than as 'PST' to avoid
- * operating-system dependence on strftime (which
- * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
- * PST as 'Pacific Standard Time.' This way we always know
- * what we're getting, and can parse it if we produce it.
- * The OS TZA string is included as a comment.
- */
-
- /* get a timezone string from the OS to include as a
- comment. */
- new_explode(local, &split);
- PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z) ", &split);
-
- /* Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
- * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
- */
- PR_snprintf(buf, sizeof buf, "%s %s %.2d %.2d:%.2d:%.2d GMT%+.4d %s%.4d",
- days[WeekDay(local)],
- months[MonthFromTime(local)],
- DateFromTime(local),
- HourFromTime(local),
- MinFromTime(local),
- SecFromTime(local),
- offset,
-
- /* don't print anything for the TZA comment if we
- got the empty string from the OS. */
- /* (balance: */
- (tzbuf[1] != ')' ? tzbuf : ""),
-
- YearFromTime(local));
- }
-
- str = JS_NewStringCopyZ(cx, buf);
- if (!str)
- return JS_FALSE;
- *rval = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- static JSBool
- date_toString(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- jsdouble *date = date_getProlog(cx, obj, argv);
- if (!date)
- return JS_FALSE;
- return date_format(cx, *date, rval);
- }
-
- #if JS_HAS_VALUEOF_HINT
- static JSBool
- date_valueOf(JSContext *cx, JSObject *obj, uintN argc,
- jsval *argv, jsval *rval)
- {
- /* If called directly with no arguments, convert to a time number. */
- if (argc == 0)
- return date_getTime(cx, obj, argc, argv, rval);
-
- /* Convert to number only if the hint was given, otherwise favor string. */
- if (argc == 1) {
- JSString *str, *str2;
-
- str = JS_ValueToString(cx, argv[0]);
- if (!str)
- return JS_FALSE;
- str2 = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
- if (!js_CompareStrings(str, str2))
- return date_getTime(cx, obj, argc, argv, rval);
- }
- return date_toString(cx, obj, argc, argv, rval);
- }
- #else
- #define date_valueOf date_getTime
- #endif
-
-
- /*
- * creation and destruction
- */
-
- static JSFunctionSpec date_static_methods[] = {
- {"UTC", date_UTC, MAXARGS },
- {"parse", date_parse, 1 },
- {0}
- };
-
- static JSFunctionSpec date_methods[] = {
- {"getTime", date_getTime, 0 },
- {"getTimezoneOffset", date_getTimezoneOffset, 0 },
- {"getYear", date_getYear, 0 },
- {"getFullYear", date_getFullYear, 0 },
- {"getUTCFullYear", date_getUTCFullYear, 0 },
- {"getMonth", date_getMonth, 0 },
- {"getUTCMonth", date_getUTCMonth, 0 },
- {"getDate", date_getDate, 0 },
- {"getUTCDate", date_getUTCDate, 0 },
- {"getDay", date_getDay, 0 },
- {"getUTCDay", date_getUTCDay, 0 },
- {"getHours", date_getHours, 0 },
- {"getUTCHours", date_getUTCHours, 0 },
- {"getMinutes", date_getMinutes, 0 },
- {"getUTCMinutes", date_getUTCMinutes, 0 },
- {"getSeconds", date_getUTCSeconds, 0 },
- {"getUTCSeconds", date_getUTCSeconds, 0 },
- {"getMilliseconds", date_getUTCMilliseconds,0 },
- {"getUTCMilliseconds",date_getUTCMilliseconds,0 },
- {"setTime", date_setTime, 1 },
- {"setYear", date_setYear, 1 },
- {"setFullYear", date_setFullYear, 1 },
- {"setUTCFullYear", date_setUTCFullYear, 1 },
- {"setMonth", date_setMonth, 1 },
- {"setUTCMonth", date_setUTCMonth, 1 },
- {"setDate", date_setDate, 1 },
- {"setUTCDate", date_setUTCDate, 1 },
- {"setHours", date_setHours, 1 },
- {"setUTCHours", date_setUTCHours, 1 },
- {"setMinutes", date_setMinutes, 1 },
- {"setUTCMinutes", date_setUTCMinutes, 1 },
- {"setSeconds", date_setSeconds, 1 },
- {"setUTCSeconds", date_setUTCSeconds, 1 },
- {"setMilliseconds", date_setMilliseconds, 1 },
- {"setUTCMilliseconds",date_setUTCMilliseconds,1 },
- {"toGMTString", date_toGMTString, 0 },
- {"toUTCString", date_toGMTString, 0 },
- {"toLocaleString", date_toLocaleString, 0 },
- {js_toString_str, date_toString, 0 },
- {js_valueOf_str, date_valueOf, 0 },
- {0}
- };
-
- static jsdouble *
- date_constructor(JSContext *cx, JSObject* obj)
- {
- jsdouble *date;
-
- date = js_NewDouble(cx, 0.0);
- if (!date)
- return NULL;
-
- JS_LOCK(cx);
- OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, DOUBLE_TO_JSVAL(date));
- JS_UNLOCK(cx);
-
- return date;
- }
-
- static JSBool
- Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- jsdouble *date;
- JSString *str;
- jsdouble d;
-
- /* Date called as function */
- if (obj->map->clasp != &date_class) {
- int64 us, ms, us2ms;
- jsdouble time;
-
- /* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
- * so compute ms from PRMJ_Now.
- */
- us = PRMJ_Now();
- LL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
- LL_DIV(ms, us, us2ms);
- LL_L2D(time, ms);
-
- return date_format(cx, time, rval);
- }
-
- /* Date called as constructor */
- if (argc == 0) {
- int64 us, ms, us2ms;
- jsdouble time;
-
- date = date_constructor(cx, obj);
- if (!date)
- return JS_FALSE;
-
- us = PRMJ_Now();
- LL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
- LL_DIV(ms, us, us2ms);
- LL_L2D(time, ms);
-
- *date = time;
- } else if (argc == 1) {
- if (!JSVAL_IS_STRING(argv[0])) {
- /* the argument is a millisecond number */
- if (!JS_ValueToNumber(cx, argv[0], &d))
- return JS_FALSE;
- date = date_constructor(cx, obj);
- if (!date)
- return JS_FALSE;
- *date = TIMECLIP(d);
- } else {
- /* the argument is a string; parse it. */
- date = date_constructor(cx, obj);
- if (!date)
- return JS_FALSE;
-
- str = JS_ValueToString(cx, argv[0]);
- if (!str)
- return JS_FALSE;
-
- if (!date_parseString(str->chars, date))
- *date = *(cx->runtime->jsNaN);
- *date = TIMECLIP(*date);
- }
- } else {
- jsdouble array[MAXARGS];
- uintN loop;
- jsdouble d;
- jsdouble day;
- jsdouble time;
-
- for (loop = 0; loop < MAXARGS; loop++) {
- if (loop < argc) {
- if (!JS_ValueToNumber(cx, argv[loop], &d))
- return JS_FALSE;
- /* if any arg is NaN, make a NaN date object
- and return */
- if (!JSDOUBLE_IS_FINITE(d)) {
- date = date_constructor(cx, obj);
- if (!date)
- return JS_FALSE;
- *date = *(cx->runtime->jsNaN);
- return JS_TRUE;
- }
- array[loop] = js_DoubleToInteger(d);
- } else {
- array[loop] = 0;
- }
- }
-
- date = date_constructor(cx, obj);
- if (!date)
- return JS_FALSE;
-
- /* adjust 2-digit years into the 20th century */
- if (array[0] >= 0 && array[0] <= 99)
- array[0] += 1900;
-
- /* if we got a 0 for 'date' (which is out of range)
- * pretend it's a 1 */
- if (array[2] < 1)
- array[2] = 1;
-
- day = MakeDay(array[0], array[1], array[2]);
-
- /* fprintf(stderr, "%f\n", day); */
-
- time = MakeTime(array[3], array[4], array[5], array[6]);
-
- /* fprintf(stderr, "%f\n", time); */
-
- time = MakeDate(day, time);
-
- /* fprintf(stderr, "%f\n", time); */
-
- time = UTC(time);
-
- /* fprintf(stderr, "%f\n", time); */
-
- *date = TIMECLIP(time);
-
- /* fprintf(stderr, "%f\n", *date); */
- }
- return JS_TRUE;
- }
-
- JSObject *
- js_InitDateClass(JSContext *cx, JSObject *obj)
- {
- /* set static LocalTZA */
- LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
- return JS_InitClass(cx, obj, NULL, &date_class, Date, MAXARGS,
- NULL, date_methods, NULL, date_static_methods);
- }
-
- JS_FRIEND_API(JSObject *)
- js_NewDateObject(JSContext* cx, int year, int mon, int mday,
- int hour, int min, int sec)
- {
- JSObject *obj;
- jsdouble *date;
- jsdouble time;
-
- obj = js_NewObject(cx, &date_class, NULL, NULL);
- if (!obj)
- return NULL;
-
- JS_DefineFunctions(cx, obj, date_methods);
-
- date = date_constructor(cx, obj);
- if (!date)
- return NULL;
-
- time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
- *date = UTC(time);
- return obj;
- }
-
- JS_FRIEND_API(int)
- js_DateGetYear(JSContext *cx, JSObject* obj)
- {
- jsdouble *date = date_getProlog(cx, obj, NULL);
-
- if (!date)
- return 0;
- return (int) YearFromTime(LocalTime(*date));
- }
-
- JS_FRIEND_API(int)
- js_DateGetMonth(JSContext *cx, JSObject* obj)
- {
- jsdouble *date = date_getProlog(cx, obj, NULL);
-
- if (!date)
- return 0;
- return (int) MonthFromTime(LocalTime(*date));
- }
-
- JS_FRIEND_API(int)
- js_DateGetDate(JSContext *cx, JSObject* obj)
- {
- jsdouble *date = date_getProlog(cx, obj, NULL);
-
- if (!date)
- return 0;
- return (int) DateFromTime(LocalTime(*date));
- }
-
- JS_FRIEND_API(int)
- js_DateGetHours(JSContext *cx, JSObject* obj)
- {
- jsdouble *date = date_getProlog(cx, obj, NULL);
-
- if (!date)
- return 0;
- return (int) HourFromTime(LocalTime(*date));
- }
-
- JS_FRIEND_API(int)
- js_DateGetMinutes(JSContext *cx, JSObject* obj)
- {
- jsdouble *date = date_getProlog(cx, obj, NULL);
-
- if (!date)
- return 0;
- return (int) MinFromTime(LocalTime(*date));
- }
-
- JS_FRIEND_API(int)
- js_DateGetSeconds(JSContext *cx, JSObject* obj)
- {
- jsdouble *date = date_getProlog(cx, obj, NULL);
-
- if (!date)
- return 0;
- return (int) SecFromTime(*date);
- }
-
- extern JS_FRIEND_API(void)
- js_DateSetYear(JSContext *cx, JSObject *obj, int year)
- {
- jsdouble local;
- jsdouble *date = date_getProlog(cx, obj, NULL);
- if (!date)
- return;
- local = LocalTime(*date);
- /* reset date if it was NaN */
- if (local != local)
- local = 0;
- local = date_msecFromDate(year,
- MonthFromTime(local),
- DateFromTime(local),
- HourFromTime(local),
- MinFromTime(local),
- SecFromTime(local),
- msFromTime(local));
- *date = UTC(local);
- }
-
- extern JS_FRIEND_API(void)
- js_DateSetMonth(JSContext *cx, JSObject *obj, int month)
- {
- jsdouble local;
- jsdouble *date = date_getProlog(cx, obj, NULL);
- if (!date)
- return;
- local = LocalTime(*date);
- /* bail if date was NaN */
- if (local != local)
- return;
- local = date_msecFromDate(YearFromTime(local),
- month,
- DateFromTime(local),
- HourFromTime(local),
- MinFromTime(local),
- SecFromTime(local),
- msFromTime(local));
- *date = UTC(local);
- }
-
- extern JS_FRIEND_API(void)
- js_DateSetDate(JSContext *cx, JSObject *obj, int date)
- {
- jsdouble local;
- jsdouble *datep = date_getProlog(cx, obj, NULL);
- if (!datep)
- return;
- local = LocalTime(*datep);
- if (local != local)
- return;
- local = date_msecFromDate(YearFromTime(local),
- MonthFromTime(local),
- date,
- HourFromTime(local),
- MinFromTime(local),
- SecFromTime(local),
- msFromTime(local));
- *datep = UTC(local);
- }
-
- extern JS_FRIEND_API(void)
- js_DateSetHours(JSContext *cx, JSObject *obj, int hours)
- {
- jsdouble local;
- jsdouble *date = date_getProlog(cx, obj, NULL);
- if (!date)
- return;
- local = LocalTime(*date);
- if (local != local)
- return;
- local = date_msecFromDate(YearFromTime(local),
- MonthFromTime(local),
- DateFromTime(local),
- hours,
- MinFromTime(local),
- SecFromTime(local),
- msFromTime(local));
- *date = UTC(local);
- }
-
- extern JS_FRIEND_API(void)
- js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes)
- {
- jsdouble local;
- jsdouble *date = date_getProlog(cx, obj, NULL);
- if (!date)
- return;
- local = LocalTime(*date);
- if (local != local)
- return;
- local = date_msecFromDate(YearFromTime(local),
- MonthFromTime(local),
- DateFromTime(local),
- HourFromTime(local),
- minutes,
- SecFromTime(local),
- msFromTime(local));
- *date = UTC(local);
- }
-
- extern JS_FRIEND_API(void)
- js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds)
- {
- jsdouble local;
- jsdouble *date = date_getProlog(cx, obj, NULL);
- if (!date)
- return;
- local = LocalTime(*date);
- if (local != local)
- return;
- local = date_msecFromDate(YearFromTime(local),
- MonthFromTime(local),
- DateFromTime(local),
- HourFromTime(local),
- MinFromTime(local),
- seconds,
- msFromTime(local));
- *date = UTC(local);
- }
-