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 (__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)) {
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 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);
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)