netscape-revival
mocha/src/mo_date.c
/*
** Mocha date methods.
**
** Ken Smith and Brendan Eich, 12/8/95
*/
#include <ctype.h>
#include <string.h>
#include "prprf.h"
#include "prmjtime.h"
#include "mo_atom.h"
#include "mo_cntxt.h"
#include "mocha.h"
#include "mochaapi.h"
#include "mochalib.h"
/***********************************************************************
**
** M o c h a D A T E O b j e c t
**
**
** The mocha 'Date' object is patterned after the java 'Date'
** object. Here is some example mocha code:
**
** today = new Date();
**
** print(today.toLocaleString());
**
** weekDay = today.getDay();
**
**
** These (java) methods are supported:
**
** UTC
** getDate
** getDay
** getHours
** getMinutes
** getMonth
** getSeconds
** getTime
** getTimezoneOffset
** getYear
** parse
** setDate
** setHours
** setMinutes
** setMonth
** setSeconds
** setTime
** setYear
** toGMTString
** toLocaleString
** toString
**
**
** These (java) methods are not supported
**
** setDay
** before
** after
** equals
** hashCode
**
**
** How is a mocha date like a java date?
**
** 1. same name -- Date
** 2. share underlying date code -- from nspr
** 3. time is milliseconds from an epoch
** 4. methods that are supported, work the same way
** 5. parse code is a direct conversion from java
**
**
** How is a mocha date different from a java date.
**
** 1. numeric form of date (such as return from getTime()) is
** a C 'double' instead of java's 'int64'.
** 2. not all java methods are supported
*/
/***********************************************************************
** Support routines and definitions
*/
#define DATE_ERROR 0
#define MAX_YEAR 3000
typedef struct DateObject {
int64 value; /* microseconds, like nspr */
PRTime split;
MochaBoolean valid;
} DateObject;
static void
date_finalize(MochaContext *mc, MochaObject *obj)
{
DateObject *dateObj;
dateObj = obj->data;
MOCHA_free(mc, dateObj);
}
static MochaClass date_class = {
"Date",
MOCHA_PropertyStub, MOCHA_PropertyStub, MOCHA_ListPropStub,
MOCHA_ResolveStub, MOCHA_ConvertStub, date_finalize
};
static void date_implode(DateObject* dateObj);
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, /* UT/UTC */
10000 + 5 * 60, 10000 + 4 * 60, /* EDT */
10000 + 6 * 60, 10000 + 5 * 60,
10000 + 7 * 60, 10000 + 6 * 60,
10000 + 8 * 60, 10000 + 7 * 60
};
static void
date_explode(DateObject* dateObj)
{
if (dateObj->valid == MOCHA_FALSE) {
MJ_PR_ExplodeTime( &dateObj->split, dateObj->value );
dateObj->value = MJ_PR_ComputeTime( &dateObj->split );
dateObj->valid = MOCHA_TRUE;
}
}
static void
date_implode(DateObject* dateObj)
{
if (dateObj->valid == MOCHA_FALSE) {
dateObj->value = MJ_PR_ComputeTime( &dateObj->split );
MJ_PR_ExplodeTime( &dateObj->split, dateObj->value );
dateObj->valid = MOCHA_TRUE;
}
}
static MochaBoolean
date_regionMatches(const char* s1, int s1off, const char* s2, int s2off,
int count, int ignoreCase)
{
int result = MOCHA_FALSE;
/* return true if matches, otherwise, false */
while ( count > 0 && *(s1+s1off) && (s2+s2off) ) {
if ( ignoreCase ) {
if ( tolower(*(s1+s1off)) != tolower(*(s2+s2off)) ) {
break;
}
}
else {
if ( *(s1+s1off) != *(s2+s2off) ) {
break;
}
}
s1off++;
s2off++;
count--;
}
if ( count == 0 ) {
result = MOCHA_TRUE;
}
return result;
}
static int64
date_localTime(int year, int mon, int mday, int hour, int min, int sec)
{
int64 result;
struct PRTimeStr split;
/* check for year out of range */
if(year < 0 ){
/* invalid date */
year = 0;
}
if(year > MAX_YEAR){
year = MAX_YEAR;
}
if ( year < 100 )
year += 1900;
split.tm_year = year;
split.tm_mon = mon;
split.tm_mday = mday;
split.tm_hour = hour;
split.tm_min = min;
split.tm_sec = sec;
split.tm_usec = 0;
split.tm_wday = 0;
split.tm_yday = 0;
split.tm_isdst = -1; /* XXX put the right value here */
result = MJ_PR_ComputeTime( &split );
return result;
}
static int64
date_UTCTime(int year, int mon, int mday, int hour, int min, int sec)
{
int64 localTime;
localTime = date_localTime(year, mon, mday, hour, min, sec);
/* adjust this "GMT" time and convert it to a local time */
return MJ_PR_ToLocal(localTime);
}
/* XXX this function must be above date_parseString to avoid a
horrid bug in the win16 1.52 compiler */
static MochaBoolean
date_UTC(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
int array[6];
int loop;
MochaFloat fval;
int64 UTCTime; /* microseconds */
int64 UTCTimeMS; /* milliseconds */
int64 oneThousand;
MochaFloat UTCTimeMSDouble;
for ( loop = 0; loop < 6; loop++ ) {
if ( loop < argc ) {
if (!mocha_DatumToNumber(mc,argv[loop],&fval))
return MOCHA_FALSE;
array[loop] = (int)fval;
} else {
array[loop] = 0;
}
}
UTCTime = date_UTCTime(array[0],array[1],array[2],
array[3],array[4],array[5]);
LL_I2L(oneThousand, 1000);
LL_DIV(UTCTimeMS, UTCTime, oneThousand);
LL_L2D(UTCTimeMSDouble, UTCTimeMS);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, UTCTimeMSDouble);
return MOCHA_TRUE;
}
static int64
date_parseString(const char* s)
{
int64 result, temp1, temp2, temp3;
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;
int tzoffset = -1;
int prevc = 0;
int limit = 0;
if (s == 0)
goto syntax;
limit = 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++;
}
if ((prevc == '+' || prevc == '-') && year>=0) {
/* 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 (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 */
return date_localTime(year, mon, mday, hour, min, sec);
}
/*
** return (date_UTCTime(year, mon, mday, hour, min, sec) +
** tzoffset * (60 * 1000));
*/
temp1 = date_UTCTime(year, mon, mday, hour, min, sec);
LL_UI2L(temp2,60000000);
LL_I2L(temp3,tzoffset);
LL_MUL(temp2,temp2,temp3);
LL_ADD(temp3,temp1,temp2);
return temp3;
syntax:
/* syntax error */
LL_I2L(result,DATE_ERROR);
return result;
}
/***********************************************************************
** methods
*/
static MochaBoolean
date_getDate(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, dateObj->split.tm_mday );
return MOCHA_TRUE;
}
static MochaBoolean
date_getDay(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, dateObj->split.tm_wday );
return MOCHA_TRUE;
}
static MochaBoolean
date_getHours(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, dateObj->split.tm_hour );
return MOCHA_TRUE;
}
static MochaBoolean
date_getMinutes(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, dateObj->split.tm_min );
return MOCHA_TRUE;
}
static MochaBoolean
date_getMonth(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, dateObj->split.tm_mon );
return MOCHA_TRUE;
}
static MochaBoolean
date_getSeconds(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, dateObj->split.tm_sec );
return MOCHA_TRUE;
}
static MochaBoolean
date_getTime(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
int64 oneThousand;
int64 valueMS;
MochaFloat theTime;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_implode( dateObj );
LL_I2L(oneThousand, 1000);
LL_DIV(valueMS, dateObj->value, oneThousand);
LL_L2D(theTime,valueMS);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, theTime);
return MOCHA_TRUE;
}
static MochaBoolean
date_getTimezoneOffset(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
int64 timezoneOffset; /* in minutes */
int64 UTCTime;
int64 currentTime;
int64 diffTime;
int64 sixtymillion; /* microseconds per minute */
MochaFloat result;
/*
** 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.
*/
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
/* get the current time from the object (computed in date_explode) */
currentTime = dateObj->value;
/* convert current time to GMT */
UTCTime = MJ_PR_ToGMT(currentTime);
/* get the DST offset but not if a Mac with weird local time */
diffTime = MJ_PR_DSTOffset(currentTime);
LL_SUB(diffTime,UTCTime,diffTime);
LL_SUB(diffTime,diffTime,currentTime);
LL_I2L(sixtymillion,60000000);
LL_DIV(timezoneOffset,diffTime,sixtymillion);
LL_L2D(result,timezoneOffset);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, result);
return MOCHA_TRUE;
}
static MochaBoolean
date_getYear(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval,
(dateObj->split.tm_year >= 1900 &&
dateObj->split.tm_year < 2000) ?
(dateObj->split.tm_year -1900) :
dateObj->split.tm_year);
return MOCHA_TRUE;
}
static MochaBoolean
date_parse(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
MochaAtom *atom;
int64 theDateTime;
int64 oneThousand;
MochaFloat result;
if (!mocha_DatumToString(mc,argv[0],&atom))
return MOCHA_FALSE;
theDateTime = date_parseString(atom_name(atom));
mocha_DropAtom(mc,atom);
LL_I2L(oneThousand, 1000);
LL_DIV(theDateTime, theDateTime, oneThousand);
LL_L2D(result, theDateTime);
MOCHA_INIT_DATUM(mc, rval, MOCHA_NUMBER, u.fval, result);
return MOCHA_TRUE;
}
static MochaBoolean
date_setDate(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
MochaFloat fval;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
if (!mocha_DatumToNumber(mc,argv[0],&fval)) return MOCHA_FALSE;
dateObj->split.tm_mday = (int)fval;
dateObj->valid = MOCHA_FALSE;
date_implode( dateObj );
return MOCHA_TRUE;
}
static MochaBoolean
date_setMinutes(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
MochaFloat fval;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
if (!mocha_DatumToNumber(mc,argv[0],&fval)) return MOCHA_FALSE;
date_explode( dateObj );
dateObj->split.tm_min = (int)fval;
dateObj->valid = MOCHA_FALSE;
date_implode( dateObj );
return MOCHA_TRUE;
}
static MochaBoolean
date_setHours(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
MochaFloat fval;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
if (!mocha_DatumToNumber(mc,argv[0],&fval)) return MOCHA_FALSE;
date_explode( dateObj );
dateObj->split.tm_hour = (int)fval;
dateObj->valid = MOCHA_FALSE;
date_implode( dateObj );
return MOCHA_TRUE;
}
static MochaBoolean
date_setMonth(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
MochaFloat fval;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
if (!mocha_DatumToNumber(mc,argv[0],&fval)) return MOCHA_FALSE;
date_explode( dateObj );
dateObj->split.tm_mon = (int)fval;
dateObj->valid = MOCHA_FALSE;
date_implode( dateObj );
return MOCHA_TRUE;
}
static MochaBoolean
date_setSeconds(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
MochaFloat fval;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
if (!mocha_DatumToNumber(mc,argv[0],&fval)) return MOCHA_FALSE;
date_explode( dateObj );
dateObj->split.tm_sec = (int)fval;
dateObj->valid = MOCHA_FALSE;
date_implode( dateObj );
return MOCHA_TRUE;
}
static MochaBoolean
date_setTime(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
MochaFloat fval;
int64 oneThousand;
int64 theTimeMS;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
if (!mocha_DatumToNumber(mc,argv[0],&fval)) return MOCHA_FALSE;
LL_I2L( oneThousand, 1000 );
LL_D2L( theTimeMS, fval );
LL_MUL( dateObj->value, theTimeMS, oneThousand );
dateObj->valid = MOCHA_FALSE;
date_explode( dateObj );
return MOCHA_TRUE;
}
static MochaBoolean
date_setYear(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
MochaFloat fval;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
if (!mocha_DatumToNumber(mc,argv[0],&fval)) return MOCHA_FALSE;
dateObj->split.tm_year = (int)fval;
if ( dateObj->split.tm_year < 100 ) {
dateObj->split.tm_year += 1900;
}
dateObj->valid = MOCHA_FALSE;
date_implode( dateObj );
return MOCHA_TRUE;
}
static MochaBoolean
date_toGMTString(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
char buf[100];
MochaAtom* atom;
struct PRTimeStr theGmtSplit;
int64 theGmtTime;
int64 us;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_implode( dateObj );
/* get the number of seconds */
LL_UI2L(us,PR_USEC_PER_SEC);
LL_DIV(theGmtTime,dateObj->value,us);
MJ_PR_gmtime(theGmtTime, &theGmtSplit );
PR_FormatTimeUSEnglish(buf, sizeof buf, "%a, %d %b %Y %H:%M:%S GMT",
&theGmtSplit);
atom = mocha_Atomize(mc, buf, ATOM_STRING);
if (atom)
MOCHA_INIT_DATUM(mc, rval, MOCHA_STRING, u.atom, atom);
else
*rval = MOCHA_empty;
return MOCHA_TRUE;
}
static MochaBoolean
date_toLocaleString(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
char buf[100];
MochaAtom* atom;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
PR_FormatTime(buf, sizeof buf, "%c", &dateObj->split);
atom = mocha_Atomize(mc, buf, ATOM_STRING);
if (atom)
MOCHA_INIT_DATUM(mc, rval, MOCHA_STRING, u.atom, atom);
else
*rval = MOCHA_empty;
return MOCHA_TRUE;
}
static MochaBoolean
date_toString(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
DateObject *dateObj;
char buf[100];
MochaAtom* atom;
if (!MOCHA_InstanceOf(mc, obj, &date_class, argv[-1].u.fun))
return MOCHA_FALSE;
dateObj = obj->data;
date_explode( dateObj );
#if XP_MAC
PR_FormatTime(buf, sizeof buf, "%a %b %d %H:%M:%S %Y",
&dateObj->split);
#else
PR_FormatTime(buf, sizeof buf, "%a %b %d %H:%M:%S %Z %Y",
&dateObj->split);
#endif
atom = mocha_Atomize(mc, buf, ATOM_STRING);
if (atom)
MOCHA_INIT_DATUM(mc, rval, MOCHA_STRING, u.atom, atom);
else
*rval = MOCHA_empty;
return MOCHA_TRUE;
}
/***********************************************************************
** creation and destruction
*/
static MochaFunctionSpec date_static_methods[] = {
{"UTC", date_UTC, 6 },
{"parse", date_parse, 1 },
{0}
};
static MochaFunctionSpec date_methods[] = {
{"getDate", date_getDate, 0 },
{"getDay", date_getDay, 0 },
{"getHours", date_getHours, 0 },
{"getMinutes", date_getMinutes, 0 },
{"getMonth", date_getMonth, 0 },
{"getSeconds", date_getSeconds, 0 },
{"getTime", date_getTime, 0 },
{"getTimezoneOffset", date_getTimezoneOffset, 0 },
{"getYear", date_getYear, 0 },
{"setDate", date_setDate, 1 },
{"setHours", date_setHours, 1 },
{"setMinutes", date_setMinutes, 1 },
{"setMonth", date_setMonth, 1 },
{"setSeconds", date_setSeconds, 1 },
{"setTime", date_setTime, 1 },
{"setYear", date_setYear, 1 },
{"toGMTString", date_toGMTString, 0 },
{"toLocaleString", date_toLocaleString, 0 },
{mocha_toStringStr, date_toString, 0 },
{mocha_valueOfStr, date_getTime, 0 },
{0}
};
static DateObject*
date_constructor(MochaContext *mc, MochaObject* obj)
{
DateObject* dateObj;
dateObj = MOCHA_malloc(mc, sizeof *dateObj);
if (!dateObj) return 0;
memset( (char*)dateObj, 0, sizeof *dateObj );
/* need to set tm_isdst to -1 to get auto date operations for
* local time to work
*/
dateObj->split.tm_isdst = -1;
obj->data = dateObj;
return dateObj;
}
static MochaBoolean
Date(MochaContext *mc, MochaObject *obj,
unsigned argc, MochaDatum *argv, MochaDatum *rval)
{
/*
** REQUIREMENT: The Date() funtion is set up so argv contains
** at least 6 arguments (even though argc doesn't reflect it).
*/
DateObject* dateObj;
if (obj->clazz != &date_class) {
PRTime prtm;
char buf[100];
MochaAtom *atom;
/* constructor call should follow 'new', but this one didn't */
MJ_PR_ExplodeTime(&prtm, MJ_PR_Now());
#if XP_MAC
PR_FormatTime(buf, sizeof buf, "%a %b %d %H:%M:%S %Y", &prtm);
#else
PR_FormatTime(buf, sizeof buf, "%a %b %d %H:%M:%S %Z %Y", &prtm);
#endif
atom = mocha_Atomize(mc, buf, ATOM_STRING);
if (atom)
MOCHA_INIT_DATUM(mc, rval, MOCHA_STRING, u.atom, atom);
else
*rval = MOCHA_empty;
return MOCHA_TRUE;
}
if ( argc == 0 ) {
dateObj = date_constructor(mc, obj);
if (!dateObj) return MOCHA_FALSE;
dateObj->value = MJ_PR_Now();
dateObj->valid = MOCHA_FALSE;
date_explode( dateObj );
} else if ( argc == 1 ) {
if ( argv[0].tag == MOCHA_NUMBER ) {
MochaFloat fval;
int64 oneThousand;
int64 theTimeMS;
dateObj = date_constructor(mc, obj);
if (!dateObj) return MOCHA_FALSE;
if (!mocha_DatumToNumber(mc,argv[0],&fval)) return MOCHA_FALSE;
LL_I2L( oneThousand, 1000 );
LL_D2L( theTimeMS,fval );
LL_MUL( dateObj->value, theTimeMS, oneThousand );
dateObj->valid = MOCHA_FALSE;
date_explode( dateObj );
} else {
MochaAtom *atom;
int64 theTime;
if (!mocha_DatumToString(mc,argv[0],&atom))
return MOCHA_FALSE;
theTime = date_parseString(atom_name(atom));
mocha_DropAtom(mc,atom);
dateObj = date_constructor(mc, obj);
if (!dateObj) return MOCHA_FALSE;
dateObj->value = theTime;
dateObj->valid = MOCHA_FALSE;
date_explode( dateObj );
}
} else {
int array[6];
int loop;
MochaFloat fval;
for ( loop = 0; loop < 6; loop++ ) {
if ( loop < argc ) {
if (!mocha_DatumToNumber(mc,argv[loop],&fval))
return MOCHA_FALSE;
array[loop] = (int)fval;
} else {
array[loop] = 0;
}
}
dateObj = date_constructor(mc, obj);
if (!dateObj) return MOCHA_FALSE;
if ( array[0] < 100 )
array[0] += 1900;
dateObj->split.tm_year = array[0];
dateObj->split.tm_mon = array[1];
dateObj->split.tm_mday = array[2];
dateObj->split.tm_hour = array[3];
dateObj->split.tm_min = array[4];
dateObj->split.tm_sec = array[5];
dateObj->split.tm_usec = 0;
dateObj->split.tm_wday = 0;
dateObj->split.tm_yday = 0;
dateObj->split.tm_isdst = -1; /* XXX put the right value here */
dateObj->valid = MOCHA_FALSE;
date_implode( dateObj );
}
return MOCHA_TRUE;
}
MochaObject *
mocha_InitDateClass(MochaContext *mc, MochaObject *obj)
{
return MOCHA_InitClass(mc, obj, &date_class, 0, Date, 6,
0, date_methods, 0, date_static_methods);
}