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> 44 #endif // HAVE_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)) {
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);
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)
double toNumber(ExecState *exec) const
Performs the ToNumber type conversion operation on this value (ECMA 9.3)
Base class for all function objects.
Represents an primitive Number value.
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
void setInternalValue(const Value &v)
Sets the internal value of the object.
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
8 bit char based string class
static Object create(ExecState *exec, ErrorType errtype=GeneralError, const char *message=0, int lineno=-1, int sourceId=-1)
Factory method for error objects.
The initial value of Function.prototype (and thus all objects created with the Function constructor) ...
Object builtinDatePrototype() const
Returns the builtin "Date.prototype" object.
bool isA(Type t) const
Checks whether or not the value is of a particular tpye.
Represents an primitive String value.
Value internalValue() const
Returns the internal value of the object.
Represents the current state of script execution.
Represents an Identifier for a Javascript object.