#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef HAVE_SYS_TIMEB_H
#define HAVE_SYS_TIMEB_H 0
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
# include <time.h>
# endif
#endif
#if HAVE_SYS_TIMEB_H
#include <sys/timeb.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif // HAVE_SYS_PARAM_H
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <ctype.h>
#include "date_object.h"
#include "error_object.h"
#include "operations.h"
#include "date_object.lut.h"
const time_t invalidDate = -1;
#if APPLE_CHANGES
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
using KJS::UString;
#define gmtime(x) gmtimeUsingCF(x)
#define localtime(x) localtimeUsingCF(x)
#define mktime(x) mktimeUsingCF(x)
#define timegm(x) timegmUsingCF(x)
#define time(x) timeUsingCF(x)
#define ctime(x) NotAllowedToCallThis()
#define strftime(a, b, c, d) NotAllowedToCallThis()
static const char * const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
static const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static struct tm *tmUsingCF(time_t clock, CFTimeZoneRef timeZone)
{
static struct tm result;
static char timeZoneCString[128];
CFAbsoluteTime absoluteTime = clock - kCFAbsoluteTimeIntervalSince1970;
CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(absoluteTime, timeZone);
CFStringRef abbreviation = CFTimeZoneCopyAbbreviation(timeZone, absoluteTime);
CFStringGetCString(abbreviation, timeZoneCString, sizeof(timeZoneCString), kCFStringEncodingASCII);
CFRelease(abbreviation);
result.tm_sec = (int)date.second;
result.tm_min = date.minute;
result.tm_hour = date.hour;
result.tm_mday = date.day;
result.tm_mon = date.month - 1;
result.tm_year = date.year - 1900;
result.tm_wday = CFAbsoluteTimeGetDayOfWeek(absoluteTime, timeZone) % 7;
result.tm_yday = CFAbsoluteTimeGetDayOfYear(absoluteTime, timeZone) - 1;
result.tm_isdst = CFTimeZoneIsDaylightSavingTime(timeZone, absoluteTime);
result.tm_gmtoff = (int)CFTimeZoneGetSecondsFromGMT(timeZone, absoluteTime);
result.tm_zone = timeZoneCString;
return &result;
}
static CFTimeZoneRef UTCTimeZone()
{
static CFTimeZoneRef zone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0);
return zone;
}
static CFTimeZoneRef CopyLocalTimeZone()
{
CFTimeZoneRef zone = CFTimeZoneCopyDefault();
if (zone) {
return zone;
}
zone = UTCTimeZone();
CFRetain(zone);
return zone;
}
static struct tm *gmtimeUsingCF(const time_t *clock)
{
return tmUsingCF(*clock, UTCTimeZone());
}
static struct tm *localtimeUsingCF(const time_t *clock)
{
CFTimeZoneRef timeZone = CopyLocalTimeZone();
struct tm *result = tmUsingCF(*clock, timeZone);
CFRelease(timeZone);
return result;
}
static time_t timetUsingCF(struct tm *tm, CFTimeZoneRef timeZone)
{
CFGregorianDate date;
date.second = tm->tm_sec;
date.minute = tm->tm_min;
date.hour = tm->tm_hour;
date.day = tm->tm_mday;
date.month = tm->tm_mon + 1;
date.year = tm->tm_year + 1900;
if (date.year < -2500 || date.year > 2500) {
return invalidDate;
}
CFAbsoluteTime absoluteTime = CFGregorianDateGetAbsoluteTime(date, timeZone);
return (time_t)(absoluteTime + kCFAbsoluteTimeIntervalSince1970);
}
static time_t mktimeUsingCF(struct tm *tm)
{
CFTimeZoneRef timeZone = CopyLocalTimeZone();
time_t result = timetUsingCF(tm, timeZone);
CFRelease(timeZone);
return result;
}
static time_t timegmUsingCF(struct tm *tm)
{
return timetUsingCF(tm, UTCTimeZone());
}
static time_t timeUsingCF(time_t *clock)
{
time_t result = (time_t)(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970);
if (clock) {
*clock = result;
}
return result;
}
static UString formatDate(struct tm &tm)
{
char buffer[100];
snprintf(buffer, sizeof(buffer), "%s %s %02d %04d",
weekdayName[(tm.tm_wday + 6) % 7],
monthName[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900);
return buffer;
}
static UString formatDateUTCVariant(struct tm &tm)
{
char buffer[100];
snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d",
weekdayName[(tm.tm_wday + 6) % 7],
tm.tm_mday, monthName[tm.tm_mon], tm.tm_year + 1900);
return buffer;
}
static UString formatTime(struct tm &tm)
{
char buffer[100];
if (tm.tm_gmtoff == 0) {
snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", tm.tm_hour, tm.tm_min, tm.tm_sec);
} else {
int offset = tm.tm_gmtoff;
if (offset < 0) {
offset = -offset;
}
snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d",
tm.tm_hour, tm.tm_min, tm.tm_sec,
tm.tm_gmtoff < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
}
return UString(buffer);
}
static UString formatLocaleDate(time_t tv)
{
LongDateTime longDateTime;
UCConvertCFAbsoluteTimeToLongDateTime(tv - kCFAbsoluteTimeIntervalSince1970, &longDateTime);
unsigned char string[257];
LongDateString(&longDateTime, longDate, string, 0);
string[string[0] + 1] = '\0';
return (char *)&string[1];
}
static UString formatLocaleTime(time_t tv)
{
LongDateTime longDateTime;
UCConvertCFAbsoluteTimeToLongDateTime(tv - kCFAbsoluteTimeIntervalSince1970, &longDateTime);
unsigned char string[257];
LongTimeString(&longDateTime, true, string, 0);
string[string[0] + 1] = '\0';
return (char *)&string[1];
}
#endif // APPLE_CHANGES
using namespace KJS;
const ClassInfo DateInstanceImp::info = {"Date", 0, 0, 0};
DateInstanceImp::DateInstanceImp(ObjectImp *proto)
: ObjectImp(proto)
{
}
const ClassInfo DatePrototypeImp::info = {"Date", 0, &dateTable, 0};
DatePrototypeImp::DatePrototypeImp(ExecState *,
ObjectPrototypeImp *objectProto)
: DateInstanceImp(objectProto)
{
Value protect(this);
setInternalValue(NumberImp::create(NaN));
}
Value DatePrototypeImp::get(ExecState *exec, const Identifier &propertyName) const
{
return lookupGetFunction<DateProtoFuncImp, ObjectImp>( exec, propertyName, &dateTable, this );
}
DateProtoFuncImp::DateProtoFuncImp(ExecState *exec, int i, int len)
: InternalFunctionImp(
static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
), id(abs(i)), utc(i<0)
{
Value protect(this);
putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
}
bool DateProtoFuncImp::implementsCall() const
{
return true;
}
Value DateProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
{
if ((id == ToString || id == ValueOf || id == GetTime || id == SetTime) &&
!thisObj.inherits(&DateInstanceImp::info)) {
Object err = Error::create(exec,TypeError);
exec->setException(err);
return err;
}
Value result;
UString s;
#if !APPLE_CHANGES
const int bufsize=100;
char timebuffer[bufsize];
CString oldlocale = setlocale(LC_TIME,NULL);
if (!oldlocale.c_str())
oldlocale = setlocale(LC_ALL, NULL);
#endif
Value v = thisObj.internalValue();
double milli = v.toNumber(exec);
if (isNaN(milli)) {
switch (id) {
case ToString:
case ToDateString:
case ToTimeString:
case ToGMTString:
case ToUTCString:
case ToLocaleString:
case ToLocaleDateString:
case ToLocaleTimeString:
return String("Invalid Date");
case ValueOf:
case GetTime:
case GetYear:
case GetFullYear:
case GetMonth:
case GetDate:
case GetDay:
case GetHours:
case GetMinutes:
case GetSeconds:
case GetMilliSeconds:
case GetTimezoneOffset:
return Number(NaN);
}
}
time_t tv = (time_t)(milli / 1000.0);
int ms = int(milli - tv * 1000.0);
struct tm *t;
if (utc)
t = gmtime(&tv);
else
t = localtime(&tv);
switch (id) {
#if APPLE_CHANGES
case ToString:
result = String(formatDate(*t) + " " + formatTime(*t));
break;
case ToDateString:
result = String(formatDate(*t));
break;
case ToTimeString:
result = String(formatTime(*t));
break;
case ToGMTString:
case ToUTCString:
result = String(formatDateUTCVariant(*t) + " " + formatTime(*t));
break;
case ToLocaleString:
result = String(formatLocaleDate(tv) + " " + formatLocaleTime(tv));
break;
case ToLocaleDateString:
result = String(formatLocaleDate(tv));
break;
case ToLocaleTimeString:
result = String(formatLocaleTime(tv));
break;
#else
case ToString:
s = ctime(&tv);
result = String(s.substr(0, s.size() - 1));
break;
case ToDateString:
case ToTimeString:
case ToGMTString:
case ToUTCString:
setlocale(LC_TIME,"C");
if (id == DateProtoFuncImp::ToDateString) {
strftime(timebuffer, bufsize, "%x",t);
} else if (id == DateProtoFuncImp::ToTimeString) {
strftime(timebuffer, bufsize, "%X",t);
} else { strftime(timebuffer, bufsize, "%a, %d %b %Y %H:%M:%S %Z", t);
}
setlocale(LC_TIME,oldlocale.c_str());
result = String(timebuffer);
break;
case ToLocaleString:
strftime(timebuffer, bufsize, "%c", t);
result = String(timebuffer);
break;
case ToLocaleDateString:
strftime(timebuffer, bufsize, "%x", t);
result = String(timebuffer);
break;
case ToLocaleTimeString:
strftime(timebuffer, bufsize, "%X", t);
result = String(timebuffer);
break;
#endif
case ValueOf:
result = Number(milli);
break;
case GetTime:
result = Number(milli);
break;
case GetYear:
if ( exec->interpreter()->compatMode() == Interpreter::IECompat )
result = Number(1900 + t->tm_year);
else
result = Number(t->tm_year);
break;
case GetFullYear:
result = Number(1900 + t->tm_year);
break;
case GetMonth:
result = Number(t->tm_mon);
break;
case GetDate:
result = Number(t->tm_mday);
break;
case GetDay:
result = Number(t->tm_wday);
break;
case GetHours:
result = Number(t->tm_hour);
break;
case GetMinutes:
result = Number(t->tm_min);
break;
case GetSeconds:
result = Number(t->tm_sec);
break;
case GetMilliSeconds:
result = Number(ms);
break;
case GetTimezoneOffset:
#if defined BSD || defined(__APPLE__)
result = Number(-t->tm_gmtoff / 60);
#else
# if defined(__BORLANDC__)
#error please add daylight savings offset here!
result = Number(_timezone / 60 - (_daylight ? 60 : 0));
# else
result = Number(( timezone / 60 - ( daylight ? 60 : 0 )));
# endif
#endif
break;
case SetTime:
milli = roundValue(exec,args[0]);
result = Number(milli);
thisObj.setInternalValue(result);
break;
case SetMilliSeconds:
ms = args[0].toInt32(exec);
break;
case SetSeconds:
t->tm_sec = args[0].toInt32(exec);
if (args.size() >= 2)
ms = args[1].toInt32(exec);
break;
case SetMinutes:
t->tm_min = args[0].toInt32(exec);
if (args.size() >= 2)
t->tm_sec = args[1].toInt32(exec);
if (args.size() >= 3)
ms = args[2].toInt32(exec);
break;
case SetHours:
t->tm_hour = args[0].toInt32(exec);
if (args.size() >= 2)
t->tm_min = args[1].toInt32(exec);
if (args.size() >= 3)
t->tm_sec = args[2].toInt32(exec);
if (args.size() >= 4)
ms = args[3].toInt32(exec);
break;
case SetDate:
t->tm_mday = args[0].toInt32(exec);
break;
case SetMonth:
t->tm_mon = args[0].toInt32(exec);
if (args.size() >= 2)
t->tm_mday = args[1].toInt32(exec);
break;
case SetFullYear:
t->tm_year = args[0].toInt32(exec) - 1900;
if (args.size() >= 2)
t->tm_mon = args[1].toInt32(exec);
if (args.size() >= 3)
t->tm_mday = args[2].toInt32(exec);
break;
case SetYear:
t->tm_year = args[0].toInt32(exec) >= 1900 ? args[0].toInt32(exec) - 1900 : args[0].toInt32(exec);
break;
}
if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
id == SetMinutes || id == SetHours || id == SetDate ||
id == SetMonth || id == SetFullYear ) {
time_t mktimeResult = mktime(t);
if (mktimeResult == invalidDate)
result = Number(NaN);
else
result = Number(mktimeResult * 1000.0 + ms);
thisObj.setInternalValue(result);
}
return result;
}
DateObjectImp::DateObjectImp(ExecState *exec,
FunctionPrototypeImp *funcProto,
DatePrototypeImp *dateProto)
: InternalFunctionImp(funcProto)
{
Value protect(this);
putDirect(prototypePropertyName, dateProto, DontEnum|DontDelete|ReadOnly);
static const Identifier parsePropertyName("parse");
putDirect(parsePropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1), DontEnum);
static const Identifier UTCPropertyName("UTC");
putDirect(UTCPropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7), DontEnum);
putDirect(lengthPropertyName, 7, ReadOnly|DontDelete|DontEnum);
}
bool DateObjectImp::implementsConstruct() const
{
return true;
}
Object DateObjectImp::construct(ExecState *exec, const List &args)
{
int numArgs = args.size();
#ifdef KJS_VERBOSE
fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs);
#endif
Value value;
if (numArgs == 0) { #if HAVE_SYS_TIMEB_H
# if defined(__BORLANDC__)
struct timeb timebuffer;
ftime(&timebuffer);
# else
struct _timeb timebuffer;
_ftime(&timebuffer);
# endif
double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);
#else
struct timeval tv;
gettimeofday(&tv, 0L);
double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);
#endif
value = Number(utc);
} else if (numArgs == 1) {
UString s = args[0].toString(exec);
double d = s.toDouble();
if (isNaN(d))
value = parseDate(s);
else
value = Number(d);
} else {
struct tm t;
memset(&t, 0, sizeof(t));
if (isNaN(args[0].toNumber(exec))
|| isNaN(args[1].toNumber(exec))
|| (numArgs >= 3 && isNaN(args[2].toNumber(exec)))
|| (numArgs >= 4 && isNaN(args[3].toNumber(exec)))
|| (numArgs >= 5 && isNaN(args[4].toNumber(exec)))
|| (numArgs >= 6 && isNaN(args[5].toNumber(exec)))
|| (numArgs >= 7 && isNaN(args[6].toNumber(exec)))) {
value = Number(NaN);
} else {
int year = args[0].toInt32(exec);
t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
t.tm_mon = args[1].toInt32(exec);
t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
t.tm_isdst = -1;
int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
time_t mktimeResult = mktime(&t);
if (mktimeResult == invalidDate)
value = Number(NaN);
else
value = Number(mktimeResult * 1000.0 + ms);
}
}
Object proto = exec->interpreter()->builtinDatePrototype();
Object ret(new DateInstanceImp(proto.imp()));
ret.setInternalValue(timeClip(value));
return ret;
}
bool DateObjectImp::implementsCall() const
{
return true;
}
Value DateObjectImp::call(ExecState *, Object &, const List &)
{
#ifdef KJS_VERBOSE
fprintf(stderr,"DateObjectImp::call - current time\n");
#endif
time_t t = time(0L);
#if APPLE_CHANGES
struct tm *tm = localtime(&t);
return String(formatDate(*tm) + " " + formatTime(*tm));
#else
UString s(ctime(&t));
return String(s.substr(0, s.size() - 1));
#endif
}
DateObjectFuncImp::DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto,
int i, int len)
: InternalFunctionImp(funcProto), id(i)
{
Value protect(this);
putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
}
bool DateObjectFuncImp::implementsCall() const
{
return true;
}
Value DateObjectFuncImp::call(ExecState *exec, Object &, const List &args)
{
if (id == Parse) {
return parseDate(args[0].toString(exec));
}
else { struct tm t;
memset(&t, 0, sizeof(t));
int n = args.size();
if (isNaN(args[0].toNumber(exec))
|| isNaN(args[1].toNumber(exec))
|| (n >= 3 && isNaN(args[2].toNumber(exec)))
|| (n >= 4 && isNaN(args[3].toNumber(exec)))
|| (n >= 5 && isNaN(args[4].toNumber(exec)))
|| (n >= 6 && isNaN(args[5].toNumber(exec)))
|| (n >= 7 && isNaN(args[6].toNumber(exec)))) {
return Number(NaN);
}
int year = args[0].toInt32(exec);
t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
t.tm_mon = args[1].toInt32(exec);
t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
time_t mktimeResult = timegm(&t);
if (mktimeResult == invalidDate)
return Number(NaN);
return Number(mktimeResult * 1000.0 + ms);
}
}
Value KJS::parseDate(const UString &u)
{
#ifdef KJS_VERBOSE
fprintf(stderr,"KJS::parseDate %s\n",u.ascii());
#endif
int firstSlash = u.find('/');
if ( firstSlash == -1 )
{
time_t seconds = KRFCDate_parseDate( u );
#ifdef KJS_VERBOSE
fprintf(stderr,"KRFCDate_parseDate returned seconds=%d\n",seconds);
#endif
if ( seconds == invalidDate )
return Number(NaN);
else
return Number(seconds * 1000.0);
}
else
{
int month = u.substr(0,firstSlash).toULong();
int secondSlash = u.find('/',firstSlash+1);
if ( secondSlash == -1 )
{
fprintf(stderr,"KJS::parseDate parsing for this format isn't implemented\n%s", u.ascii());
return Number(NaN);
}
int day = u.substr(firstSlash+1,secondSlash-firstSlash-1).toULong();
int year = u.substr(secondSlash+1).toULong();
struct tm t;
memset( &t, 0, sizeof(t) );
#if !APPLE_CHANGES
year = (year > 2037) ? 2037 : year; #endif
t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
t.tm_mon = month-1; t.tm_mday = day;
time_t seconds = mktime(&t);
if ( seconds == invalidDate )
{
#if !APPLE_CHANGES
fprintf(stderr,"KJS::parseDate mktime returned -1.\n%s", u.ascii());
#endif
return Number(NaN);
}
else
return Number(seconds * 1000.0);
}
}
static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
{
unsigned int ret = (day - 32075)
+ 1461L * (year + 4800L + (mon - 14) / 12) / 4
+ 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
- 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
- 2440588;
ret = 24*ret + hour;
ret = 60*ret + minute;
ret = 60*ret + second;
return ret;
}
static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
static const struct {
const char *tzName;
int tzOffset;
} known_zones[] = {
{ "UT", 0 },
{ "GMT", 0 },
{ "EST", -300 },
{ "EDT", -240 },
{ "CST", -360 },
{ "CDT", -300 },
{ "MST", -420 },
{ "MDT", -360 },
{ "PST", -480 },
{ "PDT", -420 },
{ 0, 0 }
};
static inline bool isSpaceOrTab(char c)
{
return c == ' ' || c == '\t';
}
time_t KJS::KRFCDate_parseDate(const UString &_date)
{
int offset = 0;
char *newPosStr;
const char *dateString = _date.ascii();
int day = 0;
char monthStr[4];
int month = -1; int year = 0;
int hour = 0;
int minute = 0;
int second = 0;
errno = 0;
while (isSpaceOrTab(*dateString))
dateString++;
const char *wordStart = dateString;
while(*dateString && !isdigit(*dateString))
{
if ( isSpaceOrTab(*dateString) && dateString - wordStart >= 3 )
{
monthStr[0] = tolower(*wordStart++);
monthStr[1] = tolower(*wordStart++);
monthStr[2] = tolower(*wordStart++);
monthStr[3] = '\0';
const char *str = strstr(haystack, monthStr);
if (str) {
int position = str - haystack;
if (position % 3 == 0) {
month = position / 3; }
}
while (isSpaceOrTab(*dateString))
dateString++;
wordStart = dateString;
}
else
dateString++;
}
while (isSpaceOrTab(*dateString))
dateString++;
if (!*dateString)
return invalidDate;
day = strtol(dateString, &newPosStr, 10);
if (errno)
return invalidDate;
dateString = newPosStr;
if ((day < 1) || (day > 31))
return invalidDate;
if (!*dateString)
return invalidDate;
if (*dateString == '-' || *dateString == ',')
dateString++;
while (isSpaceOrTab(*dateString))
dateString++;
if ( month == -1 ) {
for(int i=0; i < 3;i++)
{
if (!*dateString || (*dateString == '-') || isSpaceOrTab(*dateString))
return invalidDate;
monthStr[i] = tolower(*dateString++);
}
monthStr[3] = '\0';
newPosStr = (char*)strstr(haystack, monthStr);
if (!newPosStr || (newPosStr - haystack) % 3 != 0)
return invalidDate;
month = (newPosStr-haystack)/3;
if ((month < 0) || (month > 11))
return invalidDate;
while (*dateString && *dateString != '-' && !isSpaceOrTab(*dateString))
dateString++;
if (!*dateString)
return invalidDate;
if (*dateString != '-' && !isSpaceOrTab(*dateString))
return invalidDate;
dateString++;
}
if ((month < 0) || (month > 11))
return invalidDate;
bool gotYear = true;
year = strtol(dateString, &newPosStr, 10);
if (errno)
return invalidDate;
dateString = newPosStr;
if (*dateString == ':' || (isSpaceOrTab(*dateString) && isdigit(dateString[1])))
{
if (*dateString == ':') {
hour = year;
gotYear = false;
} else {
++dateString;
hour = strtol(dateString, &newPosStr, 10);
if (errno)
return invalidDate;
dateString = newPosStr;
}
if ((hour < 0) || (hour > 23))
return invalidDate;
if (!*dateString)
return invalidDate;
if (*dateString++ != ':')
return invalidDate;
minute = strtol(dateString, &newPosStr, 10);
if (errno)
return invalidDate;
dateString = newPosStr;
if ((minute < 0) || (minute > 59))
return invalidDate;
if (*dateString ==':') {
dateString++;
second = strtol(dateString, &newPosStr, 10);
if (errno)
return invalidDate;
dateString = newPosStr;
if ((second < 0) || (second > 59))
return invalidDate;
}
}
while (isSpaceOrTab(*dateString))
dateString++;
if (!gotYear) {
year = strtol(dateString, &newPosStr, 10);
if (errno)
return invalidDate;
while (isSpaceOrTab(*dateString))
dateString++;
}
if ((year >= 0) && (year < 50))
year += 2000;
if ((year >= 50) && (year < 100))
year += 1900;
if ((year < 1900) || (year > 2500))
return invalidDate;
if (strncasecmp(dateString, "AM", 2) == 0) {
if (hour < 1 || hour > 12)
return invalidDate;
if (hour == 12)
hour = 0;
dateString += 2;
while (isSpaceOrTab(*dateString))
dateString++;
} else if (strncasecmp(dateString, "PM", 2) == 0) {
if (hour < 1 || hour > 12)
return invalidDate;
if (hour != 12)
hour += 12;
dateString += 2;
while (isSpaceOrTab(*dateString))
dateString++;
}
bool localTime;
if (*dateString == 0) {
localTime = true;
} else {
localTime = false;
if (strncasecmp(dateString, "GMT", 3) == 0) {
dateString += 3;
}
if ((*dateString == '+') || (*dateString == '-')) {
offset = strtol(dateString, &newPosStr, 10);
if (errno || (offset < -9959) || (offset > 9959))
return invalidDate;
int sgn = (offset < 0)? -1:1;
offset = abs(offset);
offset = ((offset / 100)*60 + (offset % 100))*sgn;
} else {
for (int i=0; known_zones[i].tzName != 0; i++) {
if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
offset = known_zones[i].tzOffset;
break;
}
}
}
}
if (sizeof(time_t) == 4)
{
if ((time_t)-1 < 0)
{
if (year >= 2038)
{
year = 2038;
month = 0;
day = 1;
hour = 0;
minute = 0;
second = 0;
}
}
else
{
if (year >= 2115)
{
year = 2115;
month = 0;
day = 1;
hour = 0;
minute = 0;
second = 0;
}
}
}
time_t result;
if (localTime) {
struct tm tm;
tm.tm_year = year - 1900;
tm.tm_mon = month;
tm.tm_mday = day;
tm.tm_hour = hour;
tm.tm_min = minute;
tm.tm_sec = second;
tm.tm_isdst = -1;
result = mktime(&tm);
} else {
result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
if ((offset > 0) && (offset > result))
offset = 0;
result -= offset*60;
}
return result;
}
Value KJS::timeClip(const Value &t)
{
return t;
}