26 #if TIME_WITH_SYS_TIME
27 # include <sys/time.h>
36 #ifdef HAVE_SYS_TIMEB_H
37 #include <sys/timeb.h>
42 #ifdef HAVE_SYS_PARAM_H
43 # include <sys/param.h>
58 #include "date_object.h"
59 #include "error_object.h"
60 #include "operations.h"
62 #include "date_object.lut.h"
65 # define strncasecmp(a,b,c) _strnicmp(a,b,c)
71 const time_t invalidDate = LONG_MIN;
72 const double hoursPerDay = 24;
73 const double minutesPerHour = 60;
74 const double secondsPerMinute = 60;
75 const double msPerSecond = 1000;
76 const double msPerMinute = msPerSecond * secondsPerMinute;
77 const double msPerHour = msPerMinute * minutesPerHour;
78 const double msPerDay = msPerHour * hoursPerDay;
79 static const char *
const weekdayName[7] = {
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun" };
80 static const char *
const monthName[12] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" };
82 static UString formatDate(
struct tm &tm)
85 snprintf(buffer,
sizeof(buffer),
"%s %s %02d %04d",
86 weekdayName[(tm.tm_wday + 6) % 7],
87 monthName[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900);
91 static UString formatDateUTCVariant(
struct tm &tm)
94 snprintf(buffer,
sizeof(buffer),
"%s, %02d %s %04d",
95 weekdayName[(tm.tm_wday + 6) % 7],
96 tm.tm_mday, monthName[tm.tm_mon], tm.tm_year + 1900);
100 static UString formatTime(
struct tm &tm)
104 #if defined BSD || defined(__linux__) || defined(__APPLE__)
107 # if defined(__BORLANDC__) || defined (__CYGWIN__)
114 snprintf(buffer,
sizeof(buffer),
"%02d:%02d:%02d GMT", tm.tm_hour, tm.tm_min, tm.tm_sec);
120 snprintf(buffer,
sizeof(buffer),
"%02d:%02d:%02d GMT%c%02d%02d",
121 tm.tm_hour, tm.tm_min, tm.tm_sec,
122 tz < 0 ?
'-' :
'+', offset / (60*60), (offset / 60) % 60);
127 static int day(
double t)
129 return int(floor(t / msPerDay));
132 static double dayFromYear(
int year)
134 return 365.0 * (year - 1970)
135 + floor((year - 1969) / 4.0)
136 - floor((year - 1901) / 100.0)
137 + floor((year - 1601) / 400.0);
141 static int daysInYear(
int year)
145 else if (year % 400 == 0)
147 else if (year % 100 == 0)
154 double timeFromYear(
int year)
156 return msPerDay * dayFromYear(year);
160 int yearFromTime(
double t)
164 int y = 1970 + int(t / (365.25 * msPerDay));
166 if (timeFromYear(y) > t) {
169 }
while (timeFromYear(y) > t);
171 while (timeFromYear(y + 1) < t)
179 int weekDay(
double t)
181 int wd = (day(t) + 4) % 7;
187 static double timeZoneOffset(
const struct tm *t)
189 #if defined BSD || defined(__linux__) || defined(__APPLE__)
190 return -(t->tm_gmtoff / 60);
192 # if defined(__BORLANDC__) || defined(__CYGWIN__)
194 #if !defined(__CYGWIN__)
195 #error please add daylight savings offset here!
197 return _timezone / 60 - (t->tm_isdst > 0 ? 60 : 0);
199 return timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 );
208 static void fillStructuresUsingTimeArgs(
ExecState *exec,
const List &args,
int maxArgs,
double *ms,
struct tm *t)
210 double milliseconds = 0;
212 int numArgs = args.
size();
215 if (numArgs > maxArgs)
219 if (maxArgs >= 4 && idx < numArgs) {
221 milliseconds += args[idx++].toInt32(exec) * msPerHour;
225 if (maxArgs >= 3 && idx < numArgs) {
227 milliseconds += args[idx++].toInt32(exec) * msPerMinute;
231 if (maxArgs >= 2 && idx < numArgs) {
233 milliseconds += args[idx++].toInt32(exec) * msPerSecond;
238 milliseconds += roundValue(exec, args[idx]);
250 static void fillStructuresUsingDateArgs(
ExecState *exec,
const List &args,
int maxArgs,
double *ms,
struct tm *t)
253 int numArgs = args.
size();
256 if (numArgs > maxArgs)
260 if (maxArgs >= 3 && idx < numArgs) {
261 t->tm_year = args[idx++].toInt32(exec) - 1900;
265 if (maxArgs >= 2 && idx < numArgs) {
266 t->tm_mon = args[idx++].toInt32(exec);
272 *ms += args[idx].toInt32(exec) * msPerDay;
278 const ClassInfo DateInstanceImp::info = {
"Date", 0, 0, 0};
280 DateInstanceImp::DateInstanceImp(ObjectImp *proto)
287 const ClassInfo DatePrototypeImp::info = {
"Date", &DateInstanceImp::info, &dateTable, 0};
341 DatePrototypeImp::DatePrototypeImp(
ExecState *,
342 ObjectPrototypeImp *objectProto)
343 : DateInstanceImp(objectProto)
346 setInternalValue(
Number(NaN));
352 return lookupGetFunction<DateProtoFuncImp, ObjectImp>( exec, propertyName, &dateTable,
this );
357 DateProtoFuncImp::DateProtoFuncImp(
ExecState *exec,
int i,
int len)
359 static_cast<
FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
360 ), id(abs(i)), utc(i<0)
364 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
367 bool DateProtoFuncImp::implementsCall()
const
374 if (!thisObj.inherits(&DateInstanceImp::info)) {
379 Object err = Error::create(exec,TypeError);
380 exec->setException(err);
387 const int bufsize=100;
388 char timebuffer[bufsize];
389 CString oldlocale = setlocale(LC_TIME,NULL);
390 if (!oldlocale.c_str())
391 oldlocale = setlocale(LC_ALL, NULL);
403 case ToLocaleDateString:
404 case ToLocaleTimeString:
405 return String(
"Invalid Date");
416 case GetMilliSeconds:
417 case GetTimezoneOffset:
418 case SetMilliSeconds:
430 result =
Number(roundValue(exec,args[0]));
437 int realYearOffset = 0;
438 double milliOffset = 0.0;
439 if (milli < 0 || milli >= timeFromYear(2038)) {
441 int realYear = yearFromTime(milli);
442 int base = daysInYear(realYear) == 365 ? 2001 : 2000;
443 milliOffset = timeFromYear(base) - timeFromYear(realYear);
444 milli += milliOffset;
445 realYearOffset = realYear - base;
448 time_t tv = (time_t) floor(milli / 1000.0);
449 double ms = milli - tv * 1000.0;
452 if ( (
id == DateProtoFuncImp::ToGMTString) ||
453 (
id == DateProtoFuncImp::ToUTCString) )
455 else if (
id == DateProtoFuncImp::ToString)
464 if (realYearOffset != 0) {
465 t->tm_year += realYearOffset;
466 milli -= milliOffset;
470 m -= timeZoneOffset(t) * msPerMinute;
471 t->tm_wday = weekDay(m);
475 const char xFormat[] =
"%x";
476 const char cFormat[] =
"%c";
480 result =
String(formatDate(*t) +
" " + formatTime(*t));
483 result =
String(formatDate(*t));
486 result =
String(formatTime(*t));
490 result =
String(formatDateUTCVariant(*t) +
" " + formatTime(*t));
493 strftime(timebuffer, bufsize, cFormat, t);
494 result =
String(timebuffer);
496 case ToLocaleDateString:
497 strftime(timebuffer, bufsize, xFormat, t);
498 result =
String(timebuffer);
500 case ToLocaleTimeString:
501 strftime(timebuffer, bufsize,
"%X", t);
502 result =
String(timebuffer);
513 result =
Number(t->tm_year);
515 result =
Number(1900 + t->tm_year);
518 result =
Number(1900 + t->tm_year);
521 result =
Number(t->tm_mon);
524 result =
Number(t->tm_mday);
527 result =
Number(t->tm_wday);
530 result =
Number(t->tm_hour);
533 result =
Number(t->tm_min);
536 result =
Number(t->tm_sec);
538 case GetMilliSeconds:
541 case GetTimezoneOffset:
542 result =
Number(timeZoneOffset(t));
544 case SetMilliSeconds:
545 fillStructuresUsingTimeArgs(exec, args, 1, &ms, t);
548 fillStructuresUsingTimeArgs(exec, args, 2, &ms, t);
551 fillStructuresUsingTimeArgs(exec, args, 3, &ms, t);
554 fillStructuresUsingTimeArgs(exec, args, 4, &ms, t);
557 fillStructuresUsingDateArgs(exec, args, 1, &ms, t);
560 fillStructuresUsingDateArgs(exec, args, 2, &ms, t);
563 fillStructuresUsingDateArgs(exec, args, 3, &ms, t);
566 int y = args[0].toInt32(exec);
568 if (y >= 0 && y <= 99) {
571 fillStructuresUsingDateArgs(exec, args, 3, &ms, t);
574 t->tm_year = y - 1900;
579 if (
id == SetYear ||
id == SetMilliSeconds ||
id == SetSeconds ||
580 id == SetMinutes ||
id == SetHours ||
id == SetDate ||
581 id == SetMonth ||
id == SetFullYear ) {
582 result =
Number(makeTime(t, ms, utc));
593 DateObjectImp::DateObjectImp(
ExecState *exec,
595 DatePrototypeImp *dateProto)
601 putDirect(prototypePropertyName, dateProto, DontEnum|DontDelete|ReadOnly);
603 static const Identifier parsePropertyName(
"parse");
604 putDirect(parsePropertyName,
new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1), DontEnum);
605 static const Identifier UTCPropertyName(
"UTC");
606 putDirect(UTCPropertyName,
new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7), DontEnum);
609 putDirect(lengthPropertyName, 7, ReadOnly|DontDelete|DontEnum);
612 bool DateObjectImp::implementsConstruct()
const
620 int numArgs = args.
size();
623 fprintf(stderr,
"DateObjectImp::construct - %d args\n", numArgs);
628 #ifdef HAVE_SYS_TIMEB_H
629 # if defined(__BORLANDC__)
630 struct timeb timebuffer;
633 struct _timeb timebuffer;
636 double utc = floor((
double)timebuffer.time * 1000.0 + (
double)timebuffer.millitm);
639 gettimeofday(&tv, 0L);
640 double utc = floor((
double)tv.tv_sec * 1000.0 + (
double)tv.tv_usec / 1000.0);
643 }
else if (numArgs == 1) {
644 Value prim = args[0].toPrimitive(exec);
645 if (prim.
isA(StringType))
646 value = parseDate(prim.
toString(exec));
650 if (isNaN(args[0].toNumber(exec))
651 || isNaN(args[1].toNumber(exec))
652 || (numArgs >= 3 && isNaN(args[2].toNumber(exec)))
653 || (numArgs >= 4 && isNaN(args[3].toNumber(exec)))
654 || (numArgs >= 5 && isNaN(args[4].toNumber(exec)))
655 || (numArgs >= 6 && isNaN(args[5].toNumber(exec)))
656 || (numArgs >= 7 && isNaN(args[6].toNumber(exec)))) {
660 memset(&t, 0,
sizeof(t));
661 int year = args[0].toInt32(exec);
662 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
663 t.tm_mon = args[1].toInt32(exec);
664 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
665 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
666 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
667 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
669 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
670 value = makeTime(&t, ms,
false);
675 Object ret(
new DateInstanceImp(proto.imp()));
676 ret.setInternalValue(
Number(timeClip(value)));
680 bool DateObjectImp::implementsCall()
const
689 fprintf(stderr,
"DateObjectImp::call - current time\n");
693 struct tm *tm = localtime(&t);
694 return String(formatDate(*tm) +
" " + formatTime(*tm));
704 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
707 bool DateObjectFuncImp::implementsCall()
const
716 return Number(parseDate(args[0].toString(exec)));
719 if (isNaN(args[0].toNumber(exec))
720 || isNaN(args[1].toNumber(exec))
721 || (n >= 3 && isNaN(args[2].toNumber(exec)))
722 || (n >= 4 && isNaN(args[3].toNumber(exec)))
723 || (n >= 5 && isNaN(args[4].toNumber(exec)))
724 || (n >= 6 && isNaN(args[5].toNumber(exec)))
725 || (n >= 7 && isNaN(args[6].toNumber(exec)))) {
730 memset(&t, 0,
sizeof(t));
731 int year = args[0].toInt32(exec);
732 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
733 t.tm_mon = args[1].toInt32(exec);
734 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
735 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
736 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
737 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
738 int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
739 return Number(makeTime(&t, ms,
true));
746 double KJS::parseDate(
const UString &u)
749 fprintf(stderr,
"KJS::parseDate %s\n",u.
ascii());
751 double seconds = KRFCDate_parseDate( u );
753 return seconds == invalidDate ? NaN : seconds * 1000.0;
758 static double ymdhms_to_seconds(
int year,
int mon,
int day,
int hour,
int minute,
int second)
762 double ret = (day - 32075)
763 + 1461L * (year + 4800L + (mon - 14) / 12) / 4
764 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
765 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
768 ret = 60*ret + minute;
769 ret = 60*ret + second;
776 static const struct KnownZone {
780 const char tzName[4];
796 double KJS::makeTime(
struct tm *t,
double ms,
bool utc)
801 #if defined BSD || defined(__linux__) || defined(__APPLE__)
803 localtime_r(&zero, &t3);
804 utcOffset = t3.tm_gmtoff;
805 t->tm_isdst = t3.tm_isdst;
807 (void)localtime(&zero);
808 # if defined(__BORLANDC__) || defined(__CYGWIN__)
809 utcOffset = - _timezone;
811 utcOffset = - timezone;
820 double yearOffset = 0.0;
821 if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
827 int y = t->tm_year + 1900;
828 int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
829 const double baseTime = timeFromYear(baseYear);
830 yearOffset = timeFromYear(y) - baseTime;
831 t->tm_year = baseYear - 1900;
836 time_t tval = mktime(t) + utcOffset + int((ms + yearOffset)/1000);
838 localtime_r(&tval, &t3);
839 t->tm_isdst = t3.tm_isdst;
842 return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset;
846 static int findMonth(
const char *monthStr)
849 static const char haystack[37] =
"janfebmaraprmayjunjulaugsepoctnovdec";
851 for (
int i = 0; i < 3; ++i) {
854 needle[i] = tolower(*monthStr++);
857 const char *str = strstr(haystack, needle);
859 int position = str - haystack;
860 if (position % 3 == 0) {
869 static bool isSpaceLike(
char c)
871 return isspace(c) || c ==
',' || c ==
':' || c ==
'-';
874 double KJS::KRFCDate_parseDate(
const UString &_date)
892 bool have_tz =
false;
894 const char *dateString = _date.
ascii();
901 bool have_time =
false;
904 while(*dateString && isSpaceLike(*dateString))
907 const char *wordStart = dateString;
909 while(*dateString && !isdigit(*dateString))
911 if (isSpaceLike(*dateString) && dateString - wordStart >= 3)
913 month = findMonth(wordStart);
914 while(*dateString && isSpaceLike(*dateString))
916 wordStart = dateString;
922 if (month == -1 && dateString && wordStart != dateString) {
923 month = findMonth(wordStart);
927 while(*dateString && isSpaceLike(*dateString))
935 day = strtol(dateString, &newPosStr, 10);
938 dateString = newPosStr;
947 if (*dateString ==
'/') {
952 month = strtol(dateString, &newPosStr, 10) - 1;
955 dateString = newPosStr;
956 if (*dateString++ !=
'/' || !*dateString)
958 day = strtol(dateString, &newPosStr, 10);
961 dateString = newPosStr;
965 }
else if (*dateString ==
'/' && month == -1)
970 day = strtol(dateString, &newPosStr, 10);
973 dateString = newPosStr;
974 if (*dateString ==
'/')
982 if (*dateString ==
'-')
985 while(*dateString && isSpaceLike(*dateString))
988 if (*dateString ==
',')
993 month = findMonth(dateString);
997 while(*dateString && (*dateString !=
'-') && !isSpaceLike(*dateString))
1004 if ((*dateString !=
'-') && (*dateString !=
'/') && !isspace(*dateString))
1009 if ((month < 0) || (month > 11))
1014 if (year <= 0 && *dateString) {
1015 year = strtol(dateString, &newPosStr, 10);
1024 if (*newPosStr ==
':')
1026 else if (isSpaceLike(*newPosStr))
1027 dateString = ++newPosStr;
1031 hour = strtol(dateString, &newPosStr, 10);
1037 if (newPosStr != dateString) {
1039 dateString = newPosStr;
1041 if ((hour < 0) || (hour > 23))
1048 if (*dateString++ !=
':')
1051 minute = strtol(dateString, &newPosStr, 10);
1054 dateString = newPosStr;
1056 if ((minute < 0) || (minute > 59))
1060 if (*dateString && *dateString !=
':' && !isspace(*dateString))
1064 if (*dateString ==
':') {
1067 second = strtol(dateString, &newPosStr, 10);
1070 dateString = newPosStr;
1072 if ((second < 0) || (second > 59))
1076 if (*dateString ==
':')
1080 while(*dateString && isspace(*dateString))
1083 if (strncasecmp(dateString,
"AM", 2) == 0) {
1089 while (isspace(*dateString))
1091 }
else if (strncasecmp(dateString,
"PM", 2) == 0) {
1097 while (isspace(*dateString))
1102 dateString = newPosStr;
1109 if (strncasecmp(dateString,
"GMT", 3) == 0 ||
1110 strncasecmp(dateString,
"UTC", 3) == 0)
1116 while (*dateString && isspace(*dateString))
1119 if (strncasecmp(dateString,
"GMT", 3) == 0) {
1122 if ((*dateString ==
'+') || (*dateString ==
'-')) {
1123 offset = strtol(dateString, &newPosStr, 10);
1126 dateString = newPosStr;
1128 if ((offset < -9959) || (offset > 9959))
1131 int sgn = (offset < 0)? -1:1;
1132 offset = abs(offset);
1133 if ( *dateString ==
':' ) {
1134 int offset2 = strtol(dateString, &newPosStr, 10);
1137 dateString = newPosStr;
1138 offset = (offset*60 + offset2)*sgn;
1141 offset = ((offset / 100)*60 + (offset % 100))*sgn;
1144 for (
int i=0; i < int(
sizeof(known_zones)/
sizeof(KnownZone)); i++) {
1145 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
1146 offset = known_zones[i].tzOffset;
1147 dateString += strlen(known_zones[i].tzName);
1155 while(*dateString && isspace(*dateString))
1158 if ( *dateString && year == -1 ) {
1159 year = strtol(dateString, &newPosStr, 10);
1162 dateString = newPosStr;
1165 while (isspace(*dateString))
1170 if (*dateString !=
'\0')
1175 if ((year >= 0) && (year < 50))
1178 if ((year >= 50) && (year < 100))
1184 memset(&t, 0,
sizeof(tm));
1187 t.tm_year = year - 1900;
1196 return makeTime(&t, 0,
false) / 1000.0;
1199 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second) - offset*60;
1204 double KJS::timeClip(
double t)
1208 double at = fabs(t);
1211 return floor(at) * (t != at ? -1 : 1);
8 bit char based string class
Represents the current state of script execution.
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
The initial value of Function.prototype (and thus all objects created with the Function constructor)
Represents an Identifier for a Javascript object.
Base class for all function objects.
Object builtinDatePrototype() const
Returns the builtin "Date.prototype" object.
Represents an primitive Number value.
void setInternalValue(const Value &v)
Sets the internal value of the object.
Value internalValue() const
Returns the internal value of the object.
Represents an primitive String value.
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents.
UString toString(ExecState *exec) const
Performs the ToString type conversion operation on this value (ECMA 9.8)
bool isA(Type t) const
Checks whether or not the value is of a particular tpye.
double toNumber(ExecState *exec) const
Performs the ToNumber type conversion operation on this value (ECMA 9.3)