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 (__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(__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 struct _timeb timebuffer;
631 double utc = floor((
double)timebuffer.time * 1000.0 + (
double)timebuffer.millitm);
634 gettimeofday(&tv, 0L);
635 double utc = floor((
double)tv.tv_sec * 1000.0 + (
double)tv.tv_usec / 1000.0);
638 }
else if (numArgs == 1) {
639 Value prim = args[0].toPrimitive(exec);
640 if (prim.
isA(StringType))
641 value = parseDate(prim.
toString(exec));
645 if (isNaN(args[0].toNumber(exec))
646 || isNaN(args[1].toNumber(exec))
647 || (numArgs >= 3 && isNaN(args[2].toNumber(exec)))
648 || (numArgs >= 4 && isNaN(args[3].toNumber(exec)))
649 || (numArgs >= 5 && isNaN(args[4].toNumber(exec)))
650 || (numArgs >= 6 && isNaN(args[5].toNumber(exec)))
651 || (numArgs >= 7 && isNaN(args[6].toNumber(exec)))) {
655 memset(&t, 0,
sizeof(t));
656 int year = args[0].toInt32(exec);
657 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
658 t.tm_mon = args[1].toInt32(exec);
659 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
660 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
661 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
662 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
664 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
665 value = makeTime(&t, ms,
false);
670 Object ret(
new DateInstanceImp(proto.imp()));
671 ret.setInternalValue(
Number(timeClip(value)));
675 bool DateObjectImp::implementsCall()
const 684 fprintf(stderr,
"DateObjectImp::call - current time\n");
688 struct tm *tm = localtime(&t);
689 return String(formatDate(*tm) +
" " + formatTime(*tm));
699 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
702 bool DateObjectFuncImp::implementsCall()
const 711 return Number(parseDate(args[0].toString(exec)));
714 if (isNaN(args[0].toNumber(exec))
715 || isNaN(args[1].toNumber(exec))
716 || (n >= 3 && isNaN(args[2].toNumber(exec)))
717 || (n >= 4 && isNaN(args[3].toNumber(exec)))
718 || (n >= 5 && isNaN(args[4].toNumber(exec)))
719 || (n >= 6 && isNaN(args[5].toNumber(exec)))
720 || (n >= 7 && isNaN(args[6].toNumber(exec)))) {
725 memset(&t, 0,
sizeof(t));
726 int year = args[0].toInt32(exec);
727 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
728 t.tm_mon = args[1].toInt32(exec);
729 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
730 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
731 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
732 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
733 int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
734 return Number(makeTime(&t, ms,
true));
741 double KJS::parseDate(
const UString &u)
744 fprintf(stderr,
"KJS::parseDate %s\n",u.
ascii());
746 double seconds = KRFCDate_parseDate( u );
748 return seconds == invalidDate ? NaN : seconds * 1000.0;
753 static double ymdhms_to_seconds(
int year,
int mon,
int day,
int hour,
int minute,
int second)
757 double ret = (day - 32075)
758 + 1461L * (year + 4800L + (mon - 14) / 12) / 4
759 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
760 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
763 ret = 60*ret + minute;
764 ret = 60*ret + second;
771 static const struct KnownZone {
775 const char tzName[4];
791 double KJS::makeTime(
struct tm *t,
double ms,
bool utc)
796 #if defined BSD || defined(__linux__) || defined(__APPLE__) 798 localtime_r(&zero, &t3);
799 utcOffset = t3.tm_gmtoff;
800 t->tm_isdst = t3.tm_isdst;
802 (void)localtime(&zero);
803 # if defined(__CYGWIN__) 804 utcOffset = - _timezone;
806 utcOffset = - timezone;
815 double yearOffset = 0.0;
816 if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
822 int y = t->tm_year + 1900;
823 int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
824 const double baseTime = timeFromYear(baseYear);
825 yearOffset = timeFromYear(y) - baseTime;
826 t->tm_year = baseYear - 1900;
831 time_t tval = mktime(t) + utcOffset + int((ms + yearOffset)/1000);
833 localtime_r(&tval, &t3);
834 t->tm_isdst = t3.tm_isdst;
837 return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset;
841 static int findMonth(
const char *monthStr)
844 static const char haystack[37] =
"janfebmaraprmayjunjulaugsepoctnovdec";
846 for (
int i = 0; i < 3; ++i) {
849 needle[i] = tolower(*monthStr++);
852 const char *str = strstr(haystack, needle);
854 int position = str - haystack;
855 if (position % 3 == 0) {
864 static bool isSpaceLike(
char c)
866 return isspace(c) || c ==
',' || c ==
':' || c ==
'-';
869 double KJS::KRFCDate_parseDate(
const UString &_date)
887 bool have_tz =
false;
889 const char *dateString = _date.
ascii();
896 bool have_time =
false;
899 while(*dateString && isSpaceLike(*dateString))
902 const char *wordStart = dateString;
904 while(*dateString && !isdigit(*dateString))
906 if (isSpaceLike(*dateString) && dateString - wordStart >= 3)
908 month = findMonth(wordStart);
909 while(*dateString && isSpaceLike(*dateString))
911 wordStart = dateString;
917 if (month == -1 && dateString && wordStart != dateString) {
918 month = findMonth(wordStart);
922 while(*dateString && isSpaceLike(*dateString))
930 day = strtol(dateString, &newPosStr, 10);
933 dateString = newPosStr;
942 if (*dateString ==
'/') {
947 month = strtol(dateString, &newPosStr, 10) - 1;
950 dateString = newPosStr;
951 if (*dateString++ !=
'/' || !*dateString)
953 day = strtol(dateString, &newPosStr, 10);
956 dateString = newPosStr;
960 }
else if (*dateString ==
'/' && month == -1)
965 day = strtol(dateString, &newPosStr, 10);
968 dateString = newPosStr;
969 if (*dateString ==
'/')
977 if (*dateString ==
'-')
980 while(*dateString && isSpaceLike(*dateString))
983 if (*dateString ==
',')
988 month = findMonth(dateString);
992 while(*dateString && (*dateString !=
'-') && !isSpaceLike(*dateString))
999 if ((*dateString !=
'-') && (*dateString !=
'/') && !isspace(*dateString))
1004 if ((month < 0) || (month > 11))
1009 if (year <= 0 && *dateString) {
1010 year = strtol(dateString, &newPosStr, 10);
1019 if (*newPosStr ==
':')
1021 else if (isSpaceLike(*newPosStr))
1022 dateString = ++newPosStr;
1026 hour = strtol(dateString, &newPosStr, 10);
1032 if (newPosStr != dateString) {
1034 dateString = newPosStr;
1036 if ((hour < 0) || (hour > 23))
1043 if (*dateString++ !=
':')
1046 minute = strtol(dateString, &newPosStr, 10);
1049 dateString = newPosStr;
1051 if ((minute < 0) || (minute > 59))
1055 if (*dateString && *dateString !=
':' && !isspace(*dateString))
1059 if (*dateString ==
':') {
1062 second = strtol(dateString, &newPosStr, 10);
1065 dateString = newPosStr;
1067 if ((second < 0) || (second > 59))
1071 if (*dateString ==
':')
1075 while(*dateString && isspace(*dateString))
1078 if (strncasecmp(dateString,
"AM", 2) == 0) {
1084 while (isspace(*dateString))
1086 }
else if (strncasecmp(dateString,
"PM", 2) == 0) {
1092 while (isspace(*dateString))
1097 dateString = newPosStr;
1104 if (strncasecmp(dateString,
"GMT", 3) == 0 ||
1105 strncasecmp(dateString,
"UTC", 3) == 0)
1111 while (*dateString && isspace(*dateString))
1114 if (strncasecmp(dateString,
"GMT", 3) == 0) {
1117 if ((*dateString ==
'+') || (*dateString ==
'-')) {
1118 offset = strtol(dateString, &newPosStr, 10);
1121 dateString = newPosStr;
1123 if ((offset < -9959) || (offset > 9959))
1126 int sgn = (offset < 0)? -1:1;
1127 offset = abs(offset);
1128 if ( *dateString ==
':' ) {
1129 int offset2 = strtol(dateString, &newPosStr, 10);
1132 dateString = newPosStr;
1133 offset = (offset*60 + offset2)*sgn;
1136 offset = ((offset / 100)*60 + (offset % 100))*sgn;
1139 for (
int i=0; i < int(
sizeof(known_zones)/
sizeof(KnownZone)); i++) {
1140 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
1141 offset = known_zones[i].tzOffset;
1142 dateString += strlen(known_zones[i].tzName);
1150 while(*dateString && isspace(*dateString))
1153 if ( *dateString && year == -1 ) {
1154 year = strtol(dateString, &newPosStr, 10);
1157 dateString = newPosStr;
1160 while (isspace(*dateString))
1165 if (*dateString !=
'\0')
1170 if ((year >= 0) && (year < 50))
1173 if ((year >= 50) && (year < 100))
1179 memset(&t, 0,
sizeof(tm));
1182 t.tm_year = year - 1900;
1191 return makeTime(&t, 0,
false) / 1000.0;
1194 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second) - offset*60;
1199 double KJS::timeClip(
double t)
1203 double at = fabs(t);
1206 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.