27 #if TIME_WITH_SYS_TIME 28 # include <sys/time.h> 37 #ifdef HAVE_SYS_TIMEB_H 38 #include <sys/timeb.h> 43 #ifdef HAVE_SYS_PARAM_H 44 # include <sys/param.h> 45 #endif // HAVE_SYS_PARAM_H 59 #include "date_object.h" 60 #include "error_object.h" 61 #include "operations.h" 63 #include "date_object.lut.h" 66 # define strncasecmp(a,b,c) _strnicmp(a,b,c) 72 const time_t invalidDate = LONG_MIN;
73 const double hoursPerDay = 24;
74 const double minutesPerHour = 60;
75 const double secondsPerMinute = 60;
76 const double msPerSecond = 1000;
77 const double msPerMinute = msPerSecond * secondsPerMinute;
78 const double msPerHour = msPerMinute * minutesPerHour;
79 const double msPerDay = msPerHour * hoursPerDay;
80 static const char *
const weekdayName[7] = {
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun" };
81 static const char *
const monthName[12] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" };
83 static UString formatDate(
struct tm &tm)
86 snprintf(buffer,
sizeof(buffer),
"%s %s %02d %04d",
87 weekdayName[(tm.tm_wday + 6) % 7],
88 monthName[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900);
92 static UString formatDateUTCVariant(
struct tm &tm)
95 snprintf(buffer,
sizeof(buffer),
"%s, %02d %s %04d",
96 weekdayName[(tm.tm_wday + 6) % 7],
97 tm.tm_mday, monthName[tm.tm_mon], tm.tm_year + 1900);
101 static UString formatTime(
struct tm &tm)
105 #if defined BSD || defined(__linux__) || defined(__APPLE__) 108 # if defined(__BORLANDC__) || defined (__CYGWIN__) 115 snprintf(buffer,
sizeof(buffer),
"%02d:%02d:%02d GMT", tm.tm_hour, tm.tm_min, tm.tm_sec);
121 snprintf(buffer,
sizeof(buffer),
"%02d:%02d:%02d GMT%c%02d%02d",
122 tm.tm_hour, tm.tm_min, tm.tm_sec,
123 tz < 0 ?
'-' :
'+', offset / (60*60), (offset / 60) % 60);
128 static int day(
double t)
130 return int(floor(t / msPerDay));
133 static double dayFromYear(
int year)
135 return 365.0 * (year - 1970)
136 + floor((year - 1969) / 4.0)
137 - floor((year - 1901) / 100.0)
138 + floor((year - 1601) / 400.0);
142 static int daysInYear(
int year)
146 else if (year % 400 == 0)
148 else if (year % 100 == 0)
155 double timeFromYear(
int year)
157 return msPerDay * dayFromYear(year);
161 int yearFromTime(
double t)
165 int y = 1970 + int(t / (365.25 * msPerDay));
167 if (timeFromYear(y) > t) {
170 }
while (timeFromYear(y) > t);
172 while (timeFromYear(y + 1) < t)
180 int weekDay(
double t)
182 int wd = (day(t) + 4) % 7;
188 static double timeZoneOffset(
const struct tm *t)
190 #if defined BSD || defined(__linux__) || defined(__APPLE__) 191 return -(t->tm_gmtoff / 60);
193 # if defined(__BORLANDC__) || defined(__CYGWIN__) 195 #if !defined(__CYGWIN__) 196 #error please add daylight savings offset here! 198 return _timezone / 60 - (t->tm_isdst > 0 ? 60 : 0);
200 return timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 );
209 static void fillStructuresUsingTimeArgs(
ExecState *exec,
const List &args,
int maxArgs,
double *ms,
struct tm *t)
211 double milliseconds = 0;
213 int numArgs = args.
size();
216 if (numArgs > maxArgs)
220 if (maxArgs >= 4 && idx < numArgs) {
222 milliseconds += args[idx++].toInt32(exec) * msPerHour;
226 if (maxArgs >= 3 && idx < numArgs) {
228 milliseconds += args[idx++].toInt32(exec) * msPerMinute;
232 if (maxArgs >= 2 && idx < numArgs) {
234 milliseconds += args[idx++].toInt32(exec) * msPerSecond;
239 milliseconds += roundValue(exec, args[idx]);
251 static void fillStructuresUsingDateArgs(
ExecState *exec,
const List &args,
int maxArgs,
double *ms,
struct tm *t)
254 int numArgs = args.
size();
257 if (numArgs > maxArgs)
261 if (maxArgs >= 3 && idx < numArgs) {
262 t->tm_year = args[idx++].toInt32(exec) - 1900;
266 if (maxArgs >= 2 && idx < numArgs) {
267 t->tm_mon = args[idx++].toInt32(exec);
273 *ms += args[idx].toInt32(exec) * msPerDay;
279 const ClassInfo DateInstanceImp::info = {
"Date", 0, 0, 0};
281 DateInstanceImp::DateInstanceImp(ObjectImp *proto)
288 const ClassInfo DatePrototypeImp::info = {
"Date", &DateInstanceImp::info, &dateTable, 0};
342 DatePrototypeImp::DatePrototypeImp(
ExecState *,
343 ObjectPrototypeImp *objectProto)
344 : DateInstanceImp(objectProto)
347 setInternalValue(
Number(NaN));
353 return lookupGetFunction<DateProtoFuncImp, ObjectImp>( exec, propertyName, &dateTable, this );
358 DateProtoFuncImp::DateProtoFuncImp(
ExecState *exec,
int i,
int len)
360 static_cast<
FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
361 ), id(abs(i)), utc(i<0)
365 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
368 bool DateProtoFuncImp::implementsCall()
const 375 if (!thisObj.inherits(&DateInstanceImp::info)) {
381 exec->setException(err);
388 const int bufsize=100;
389 char timebuffer[bufsize];
390 CString oldlocale = setlocale(LC_TIME,NULL);
391 if (!oldlocale.c_str())
392 oldlocale = setlocale(LC_ALL, NULL);
404 case ToLocaleDateString:
405 case ToLocaleTimeString:
406 return String(
"Invalid Date");
417 case GetMilliSeconds:
418 case GetTimezoneOffset:
419 case SetMilliSeconds:
431 result =
Number(roundValue(exec,args[0]));
438 int realYearOffset = 0;
439 double milliOffset = 0.0;
440 if (milli < 0 || milli >= timeFromYear(2038)) {
442 int realYear = yearFromTime(milli);
443 int base = daysInYear(realYear) == 365 ? 2001 : 2000;
444 milliOffset = timeFromYear(base) - timeFromYear(realYear);
445 milli += milliOffset;
446 realYearOffset = realYear - base;
449 time_t tv = (time_t) floor(milli / 1000.0);
450 double ms = milli - tv * 1000.0;
453 if ( (
id == DateProtoFuncImp::ToGMTString) ||
454 (
id == DateProtoFuncImp::ToUTCString) )
456 else if (
id == DateProtoFuncImp::ToString)
465 if (realYearOffset != 0) {
466 t->tm_year += realYearOffset;
467 milli -= milliOffset;
471 m -= timeZoneOffset(t) * msPerMinute;
472 t->tm_wday = weekDay(m);
476 const char xFormat[] =
"%x";
477 const char cFormat[] =
"%c";
481 result =
String(formatDate(*t) +
" " + formatTime(*t));
484 result =
String(formatDate(*t));
487 result =
String(formatTime(*t));
491 result =
String(formatDateUTCVariant(*t) +
" " + formatTime(*t));
494 strftime(timebuffer, bufsize, cFormat, t);
495 result =
String(timebuffer);
497 case ToLocaleDateString:
498 strftime(timebuffer, bufsize, xFormat, t);
499 result =
String(timebuffer);
501 case ToLocaleTimeString:
502 strftime(timebuffer, bufsize,
"%X", t);
503 result =
String(timebuffer);
514 result =
Number(t->tm_year);
516 result =
Number(1900 + t->tm_year);
519 result =
Number(1900 + t->tm_year);
522 result =
Number(t->tm_mon);
525 result =
Number(t->tm_mday);
528 result =
Number(t->tm_wday);
531 result =
Number(t->tm_hour);
534 result =
Number(t->tm_min);
537 result =
Number(t->tm_sec);
539 case GetMilliSeconds:
542 case GetTimezoneOffset:
543 result =
Number(timeZoneOffset(t));
545 case SetMilliSeconds:
546 fillStructuresUsingTimeArgs(exec, args, 1, &ms, t);
549 fillStructuresUsingTimeArgs(exec, args, 2, &ms, t);
552 fillStructuresUsingTimeArgs(exec, args, 3, &ms, t);
555 fillStructuresUsingTimeArgs(exec, args, 4, &ms, t);
558 fillStructuresUsingDateArgs(exec, args, 1, &ms, t);
561 fillStructuresUsingDateArgs(exec, args, 2, &ms, t);
564 fillStructuresUsingDateArgs(exec, args, 3, &ms, t);
567 int y = args[0].toInt32(exec);
569 if (y >= 0 && y <= 99) {
572 fillStructuresUsingDateArgs(exec, args, 3, &ms, t);
575 t->tm_year = y - 1900;
580 if (
id == SetYear ||
id == SetMilliSeconds ||
id == SetSeconds ||
581 id == SetMinutes ||
id == SetHours ||
id == SetDate ||
582 id == SetMonth ||
id == SetFullYear ) {
583 result =
Number(makeTime(t, ms, utc));
594 DateObjectImp::DateObjectImp(
ExecState *exec,
596 DatePrototypeImp *dateProto)
602 putDirect(prototypePropertyName, dateProto, DontEnum|DontDelete|ReadOnly);
604 static const Identifier parsePropertyName(
"parse");
605 putDirect(parsePropertyName,
new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1), DontEnum);
606 static const Identifier UTCPropertyName(
"UTC");
607 putDirect(UTCPropertyName,
new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7), DontEnum);
610 putDirect(lengthPropertyName, 7, ReadOnly|DontDelete|DontEnum);
613 bool DateObjectImp::implementsConstruct()
const 621 int numArgs = args.
size();
624 fprintf(stderr,
"DateObjectImp::construct - %d args\n", numArgs);
629 #ifdef HAVE_SYS_TIMEB_H 630 # if defined(__BORLANDC__) 631 struct timeb timebuffer;
634 struct _timeb timebuffer;
637 double utc = floor((
double)timebuffer.time * 1000.0 + (
double)timebuffer.millitm);
640 gettimeofday(&tv, 0L);
641 double utc = floor((
double)tv.tv_sec * 1000.0 + (
double)tv.tv_usec / 1000.0);
644 }
else if (numArgs == 1) {
645 Value prim = args[0].toPrimitive(exec);
646 if (prim.
isA(StringType))
647 value = parseDate(prim.
toString(exec));
651 if (isNaN(args[0].toNumber(exec))
652 || isNaN(args[1].toNumber(exec))
653 || (numArgs >= 3 && isNaN(args[2].toNumber(exec)))
654 || (numArgs >= 4 && isNaN(args[3].toNumber(exec)))
655 || (numArgs >= 5 && isNaN(args[4].toNumber(exec)))
656 || (numArgs >= 6 && isNaN(args[5].toNumber(exec)))
657 || (numArgs >= 7 && isNaN(args[6].toNumber(exec)))) {
661 memset(&t, 0,
sizeof(t));
662 int year = args[0].toInt32(exec);
663 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
664 t.tm_mon = args[1].toInt32(exec);
665 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
666 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
667 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
668 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
670 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
671 value = makeTime(&t, ms,
false);
676 Object ret(
new DateInstanceImp(proto.imp()));
677 ret.setInternalValue(
Number(timeClip(value)));
681 bool DateObjectImp::implementsCall()
const 690 fprintf(stderr,
"DateObjectImp::call - current time\n");
694 struct tm *tm = localtime(&t);
695 return String(formatDate(*tm) +
" " + formatTime(*tm));
705 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
708 bool DateObjectFuncImp::implementsCall()
const 717 return Number(parseDate(args[0].toString(exec)));
720 if (isNaN(args[0].toNumber(exec))
721 || isNaN(args[1].toNumber(exec))
722 || (n >= 3 && isNaN(args[2].toNumber(exec)))
723 || (n >= 4 && isNaN(args[3].toNumber(exec)))
724 || (n >= 5 && isNaN(args[4].toNumber(exec)))
725 || (n >= 6 && isNaN(args[5].toNumber(exec)))
726 || (n >= 7 && isNaN(args[6].toNumber(exec)))) {
731 memset(&t, 0,
sizeof(t));
732 int year = args[0].toInt32(exec);
733 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
734 t.tm_mon = args[1].toInt32(exec);
735 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
736 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
737 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
738 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
739 int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
740 return Number(makeTime(&t, ms,
true));
747 double KJS::parseDate(
const UString &u)
750 fprintf(stderr,
"KJS::parseDate %s\n",u.
ascii());
752 double seconds = KRFCDate_parseDate( u );
754 return seconds == invalidDate ? NaN : seconds * 1000.0;
759 static double ymdhms_to_seconds(
int year,
int mon,
int day,
int hour,
int minute,
int second)
763 double ret = (day - 32075)
764 + 1461L * (year + 4800L + (mon - 14) / 12) / 4
765 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
766 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
769 ret = 60*ret + minute;
770 ret = 60*ret + second;
777 static const struct KnownZone {
781 const char tzName[4];
797 double KJS::makeTime(
struct tm *t,
double ms,
bool utc)
802 #if defined BSD || defined(__linux__) || defined(__APPLE__) 804 localtime_r(&zero, &t3);
805 utcOffset = t3.tm_gmtoff;
806 t->tm_isdst = t3.tm_isdst;
808 (void)localtime(&zero);
809 # if defined(__BORLANDC__) || defined(__CYGWIN__) 810 utcOffset = - _timezone;
812 utcOffset = - timezone;
821 double yearOffset = 0.0;
822 if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
828 int y = t->tm_year + 1900;
829 int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
830 const double baseTime = timeFromYear(baseYear);
831 yearOffset = timeFromYear(y) - baseTime;
832 t->tm_year = baseYear - 1900;
837 time_t tval = mktime(t) + utcOffset + int((ms + yearOffset)/1000);
839 localtime_r(&tval, &t3);
840 t->tm_isdst = t3.tm_isdst;
843 return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset;
847 static int findMonth(
const char *monthStr)
850 static const char haystack[37] =
"janfebmaraprmayjunjulaugsepoctnovdec";
852 for (
int i = 0; i < 3; ++i) {
855 needle[i] = tolower(*monthStr++);
858 const char *str = strstr(haystack, needle);
860 int position = str - haystack;
861 if (position % 3 == 0) {
870 static bool isSpaceLike(
char c)
872 return isspace(c) || c ==
',' || c ==
':' || c ==
'-';
875 double KJS::KRFCDate_parseDate(
const UString &_date)
893 bool have_tz =
false;
895 const char *dateString = _date.
ascii();
902 bool have_time =
false;
905 while(*dateString && isSpaceLike(*dateString))
908 const char *wordStart = dateString;
910 while(*dateString && !isdigit(*dateString))
912 if (isSpaceLike(*dateString) && dateString - wordStart >= 3)
914 month = findMonth(wordStart);
915 while(*dateString && isSpaceLike(*dateString))
917 wordStart = dateString;
923 if (month == -1 && dateString && wordStart != dateString) {
924 month = findMonth(wordStart);
928 while(*dateString && isSpaceLike(*dateString))
936 day = strtol(dateString, &newPosStr, 10);
939 dateString = newPosStr;
948 if (*dateString ==
'/') {
953 month = strtol(dateString, &newPosStr, 10) - 1;
956 dateString = newPosStr;
957 if (*dateString++ !=
'/' || !*dateString)
959 day = strtol(dateString, &newPosStr, 10);
962 dateString = newPosStr;
966 }
else if (*dateString ==
'/' && month == -1)
971 day = strtol(dateString, &newPosStr, 10);
974 dateString = newPosStr;
975 if (*dateString ==
'/')
983 if (*dateString ==
'-')
986 while(*dateString && isSpaceLike(*dateString))
989 if (*dateString ==
',')
994 month = findMonth(dateString);
998 while(*dateString && (*dateString !=
'-') && !isSpaceLike(*dateString))
1005 if ((*dateString !=
'-') && (*dateString !=
'/') && !isspace(*dateString))
1010 if ((month < 0) || (month > 11))
1015 if (year <= 0 && *dateString) {
1016 year = strtol(dateString, &newPosStr, 10);
1025 if (*newPosStr ==
':')
1027 else if (isSpaceLike(*newPosStr))
1028 dateString = ++newPosStr;
1032 hour = strtol(dateString, &newPosStr, 10);
1038 if (newPosStr != dateString) {
1040 dateString = newPosStr;
1042 if ((hour < 0) || (hour > 23))
1049 if (*dateString++ !=
':')
1052 minute = strtol(dateString, &newPosStr, 10);
1055 dateString = newPosStr;
1057 if ((minute < 0) || (minute > 59))
1061 if (*dateString && *dateString !=
':' && !isspace(*dateString))
1065 if (*dateString ==
':') {
1068 second = strtol(dateString, &newPosStr, 10);
1071 dateString = newPosStr;
1073 if ((second < 0) || (second > 59))
1077 if (*dateString ==
':')
1081 while(*dateString && isspace(*dateString))
1084 if (strncasecmp(dateString,
"AM", 2) == 0) {
1090 while (isspace(*dateString))
1092 }
else if (strncasecmp(dateString,
"PM", 2) == 0) {
1098 while (isspace(*dateString))
1103 dateString = newPosStr;
1110 if (strncasecmp(dateString,
"GMT", 3) == 0 ||
1111 strncasecmp(dateString,
"UTC", 3) == 0)
1117 while (*dateString && isspace(*dateString))
1120 if (strncasecmp(dateString,
"GMT", 3) == 0) {
1123 if ((*dateString ==
'+') || (*dateString ==
'-')) {
1124 offset = strtol(dateString, &newPosStr, 10);
1127 dateString = newPosStr;
1129 if ((offset < -9959) || (offset > 9959))
1132 int sgn = (offset < 0)? -1:1;
1133 offset = abs(offset);
1134 if ( *dateString ==
':' ) {
1135 int offset2 = strtol(dateString, &newPosStr, 10);
1138 dateString = newPosStr;
1139 offset = (offset*60 + offset2)*sgn;
1142 offset = ((offset / 100)*60 + (offset % 100))*sgn;
1145 for (
int i=0; i < int(
sizeof(known_zones)/
sizeof(KnownZone)); i++) {
1146 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
1147 offset = known_zones[i].tzOffset;
1148 dateString += strlen(known_zones[i].tzName);
1156 while(*dateString && isspace(*dateString))
1159 if ( *dateString && year == -1 ) {
1160 year = strtol(dateString, &newPosStr, 10);
1163 dateString = newPosStr;
1166 while (isspace(*dateString))
1171 if (*dateString !=
'\0')
1176 if ((year >= 0) && (year < 50))
1179 if ((year >= 50) && (year < 100))
1185 memset(&t, 0,
sizeof(tm));
1188 t.tm_year = year - 1900;
1197 return makeTime(&t, 0,
false) / 1000.0;
1200 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second) - offset*60;
1205 double KJS::timeClip(
double t)
1209 double at = fabs(t);
1212 return floor(at) * (t != at ? -1 : 1);
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents...
Base class for all function objects.
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
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.
Object builtinDatePrototype() const
Returns the builtin "Date.prototype" object.
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) ...
double toNumber(ExecState *exec) const
Performs the ToNumber type conversion operation on this value (ECMA 9.3)
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.
UString toString(ExecState *exec) const
Performs the ToString type conversion operation on this value (ECMA 9.8)
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
Represents the current state of script execution.
Represents an Identifier for a Javascript object.