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...
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.