kjs Library API Documentation

date_object.cpp

00001 // -*- c-basic-offset: 2 -*- 00002 /* 00003 * This file is part of the KDE libraries 00004 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 00005 * Copyright (C) 2003 Apple Computer, Inc. 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00020 * 00021 */ 00022 00023 #ifdef HAVE_CONFIG_H 00024 #include <config.h> 00025 #endif 00026 #ifndef HAVE_SYS_TIMEB_H 00027 #define HAVE_SYS_TIMEB_H 0 00028 #endif 00029 00030 #if TIME_WITH_SYS_TIME 00031 # include <sys/time.h> 00032 # include <time.h> 00033 #else 00034 #if HAVE_SYS_TIME_H 00035 #include <sys/time.h> 00036 #else 00037 # include <time.h> 00038 # endif 00039 #endif 00040 #if HAVE_SYS_TIMEB_H 00041 #include <sys/timeb.h> 00042 #endif 00043 00044 #ifdef HAVE_SYS_PARAM_H 00045 # include <sys/param.h> 00046 #endif // HAVE_SYS_PARAM_H 00047 00048 #include <math.h> 00049 #include <string.h> 00050 #include <stdio.h> 00051 #include <stdlib.h> 00052 #include <locale.h> 00053 #include <ctype.h> 00054 00055 #include "date_object.h" 00056 #include "error_object.h" 00057 #include "operations.h" 00058 00059 #include "date_object.lut.h" 00060 00061 const time_t invalidDate = -1; 00062 00063 using namespace KJS; 00064 00065 // ------------------------------ DateInstanceImp ------------------------------ 00066 00067 const ClassInfo DateInstanceImp::info = {"Date", 0, 0, 0}; 00068 00069 DateInstanceImp::DateInstanceImp(ObjectImp *proto) 00070 : ObjectImp(proto) 00071 { 00072 } 00073 00074 // ------------------------------ DatePrototypeImp ----------------------------- 00075 00076 const ClassInfo DatePrototypeImp::info = {"Date", 0, &dateTable, 0}; 00077 00078 /* Source for date_object.lut.h 00079 We use a negative ID to denote the "UTC" variant. 00080 @begin dateTable 61 00081 toString DateProtoFuncImp::ToString DontEnum|Function 0 00082 toUTCString DateProtoFuncImp::ToUTCString DontEnum|Function 0 00083 toDateString DateProtoFuncImp::ToDateString DontEnum|Function 0 00084 toTimeString DateProtoFuncImp::ToTimeString DontEnum|Function 0 00085 toLocaleString DateProtoFuncImp::ToLocaleString DontEnum|Function 0 00086 toLocaleDateString DateProtoFuncImp::ToLocaleDateString DontEnum|Function 0 00087 toLocaleTimeString DateProtoFuncImp::ToLocaleTimeString DontEnum|Function 0 00088 valueOf DateProtoFuncImp::ValueOf DontEnum|Function 0 00089 getTime DateProtoFuncImp::GetTime DontEnum|Function 0 00090 getFullYear DateProtoFuncImp::GetFullYear DontEnum|Function 0 00091 getUTCFullYear -DateProtoFuncImp::GetFullYear DontEnum|Function 0 00092 toGMTString DateProtoFuncImp::ToGMTString DontEnum|Function 0 00093 getMonth DateProtoFuncImp::GetMonth DontEnum|Function 0 00094 getUTCMonth -DateProtoFuncImp::GetMonth DontEnum|Function 0 00095 getDate DateProtoFuncImp::GetDate DontEnum|Function 0 00096 getUTCDate -DateProtoFuncImp::GetDate DontEnum|Function 0 00097 getDay DateProtoFuncImp::GetDay DontEnum|Function 0 00098 getUTCDay -DateProtoFuncImp::GetDay DontEnum|Function 0 00099 getHours DateProtoFuncImp::GetHours DontEnum|Function 0 00100 getUTCHours -DateProtoFuncImp::GetHours DontEnum|Function 0 00101 getMinutes DateProtoFuncImp::GetMinutes DontEnum|Function 0 00102 getUTCMinutes -DateProtoFuncImp::GetMinutes DontEnum|Function 0 00103 getSeconds DateProtoFuncImp::GetSeconds DontEnum|Function 0 00104 getUTCSeconds -DateProtoFuncImp::GetSeconds DontEnum|Function 0 00105 getMilliseconds DateProtoFuncImp::GetMilliSeconds DontEnum|Function 0 00106 getUTCMilliseconds -DateProtoFuncImp::GetMilliSeconds DontEnum|Function 0 00107 getTimezoneOffset DateProtoFuncImp::GetTimezoneOffset DontEnum|Function 0 00108 setTime DateProtoFuncImp::SetTime DontEnum|Function 1 00109 setMilliseconds DateProtoFuncImp::SetMilliSeconds DontEnum|Function 1 00110 setUTCMilliseconds -DateProtoFuncImp::SetMilliSeconds DontEnum|Function 1 00111 setSeconds DateProtoFuncImp::SetSeconds DontEnum|Function 2 00112 setUTCSeconds -DateProtoFuncImp::SetSeconds DontEnum|Function 2 00113 setMinutes DateProtoFuncImp::SetMinutes DontEnum|Function 3 00114 setUTCMinutes -DateProtoFuncImp::SetMinutes DontEnum|Function 3 00115 setHours DateProtoFuncImp::SetHours DontEnum|Function 4 00116 setUTCHours -DateProtoFuncImp::SetHours DontEnum|Function 4 00117 setDate DateProtoFuncImp::SetDate DontEnum|Function 1 00118 setUTCDate -DateProtoFuncImp::SetDate DontEnum|Function 1 00119 setMonth DateProtoFuncImp::SetMonth DontEnum|Function 2 00120 setUTCMonth -DateProtoFuncImp::SetMonth DontEnum|Function 2 00121 setFullYear DateProtoFuncImp::SetFullYear DontEnum|Function 3 00122 setUTCFullYear -DateProtoFuncImp::SetFullYear DontEnum|Function 3 00123 setYear DateProtoFuncImp::SetYear DontEnum|Function 1 00124 getYear DateProtoFuncImp::GetYear DontEnum|Function 0 00125 toGMTString DateProtoFuncImp::ToGMTString DontEnum|Function 0 00126 @end 00127 */ 00128 // ECMA 15.9.4 00129 00130 DatePrototypeImp::DatePrototypeImp(ExecState *, 00131 ObjectPrototypeImp *objectProto) 00132 : DateInstanceImp(objectProto) 00133 { 00134 Value protect(this); 00135 setInternalValue(Number(NaN)); 00136 // The constructor will be added later, after DateObjectImp has been built 00137 } 00138 00139 Value DatePrototypeImp::get(ExecState *exec, const Identifier &propertyName) const 00140 { 00141 return lookupGetFunction<DateProtoFuncImp, ObjectImp>( exec, propertyName, &dateTable, this ); 00142 } 00143 00144 // ------------------------------ DateProtoFuncImp ----------------------------- 00145 00146 DateProtoFuncImp::DateProtoFuncImp(ExecState *exec, int i, int len) 00147 : InternalFunctionImp( 00148 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()) 00149 ), id(abs(i)), utc(i<0) 00150 // We use a negative ID to denote the "UTC" variant. 00151 { 00152 Value protect(this); 00153 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum); 00154 } 00155 00156 bool DateProtoFuncImp::implementsCall() const 00157 { 00158 return true; 00159 } 00160 00161 Value DateProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args) 00162 { 00163 if ((id == ToString || id == ValueOf || id == GetTime || id == SetTime) && 00164 !thisObj.inherits(&DateInstanceImp::info)) { 00165 // non-generic function called on non-date object 00166 00167 // ToString and ValueOf are generic according to the spec, but the mozilla 00168 // tests suggest otherwise... 00169 Object err = Error::create(exec,TypeError); 00170 exec->setException(err); 00171 return err; 00172 } 00173 00174 00175 Value result; 00176 UString s; 00177 const int bufsize=100; 00178 char timebuffer[bufsize]; 00179 CString oldlocale = setlocale(LC_TIME,NULL); 00180 if (!oldlocale.c_str()) 00181 oldlocale = setlocale(LC_ALL, NULL); 00182 Value v = thisObj.internalValue(); 00183 double milli = v.toNumber(exec); 00184 // special case: time value is NaN 00185 if (isNaN(milli)) { 00186 switch (id) { 00187 case ToString: 00188 case ToDateString: 00189 case ToTimeString: 00190 case ToGMTString: 00191 case ToUTCString: 00192 case ToLocaleString: 00193 case ToLocaleDateString: 00194 case ToLocaleTimeString: 00195 return String("Invalid Date"); 00196 case ValueOf: 00197 case GetTime: 00198 case GetYear: 00199 case GetFullYear: 00200 case GetMonth: 00201 case GetDate: 00202 case GetDay: 00203 case GetHours: 00204 case GetMinutes: 00205 case GetSeconds: 00206 case GetMilliSeconds: 00207 case GetTimezoneOffset: 00208 return Number(NaN); 00209 } 00210 } 00211 time_t tv = (time_t) floor(milli / 1000.0); 00212 int ms = int(milli - tv * 1000.0); 00213 00214 // As long as we're using time_t we need to 'truncate' to avoid 'wrapping'. 00215 // Real long term solutions include: writing our own 64-bit-based date/time class, 00216 // using wxWindow's datetime.cpp (in wxBase), using QDateTime... or shifting 00217 // to a time_t range by substracting a big enough number of years.... 00218 if (sizeof(time_t) == 4) 00219 { 00220 // If time_t is signed, the bigger it can be is 2^31-1 00221 if ( (time_t)-1 < 0 ) { 00222 if ( floor(milli / 1000.0) > ((double)((uint)1<<31)-1) ) { 00223 #ifdef KJS_VERBOSE 00224 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(milli/(1000.0*365.25*86400)+1970)); 00225 #endif 00226 tv = ((uint)1<<31)-1; 00227 ms = 0; 00228 } 00229 } 00230 else 00231 // time_t is unsigned, the bigger it can be is 2^32-1, aka (uint)-1 00232 if ( floor(milli / 1000.0) > ((double)(uint)-1) ) { 00233 #ifdef KJS_VERBOSE 00234 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(milli/(1000.0*365.25*86400)+1970)); 00235 #endif 00236 tv = (uint)-1; 00237 ms = 0; 00238 } 00239 } 00240 00241 struct tm *t; 00242 if (utc) 00243 t = gmtime(&tv); 00244 else 00245 t = localtime(&tv); 00246 00247 // trick gcc. We don't want the Y2K warnings. 00248 const char xFormat[] = "%x"; 00249 const char cFormat[] = "%c"; 00250 00251 switch (id) { 00252 case ToString: 00253 case ToDateString: 00254 case ToTimeString: 00255 case ToGMTString: 00256 case ToUTCString: 00257 setlocale(LC_TIME,"C"); 00258 if (id == DateProtoFuncImp::ToDateString) { 00259 strftime(timebuffer, bufsize, xFormat, t); 00260 } else if (id == DateProtoFuncImp::ToTimeString) { 00261 strftime(timebuffer, bufsize, "%X",t); 00262 } else { // ToString, toGMTString & toUTCString 00263 t = (id == ToString ? localtime(&tv) : gmtime(&tv)); 00264 strftime(timebuffer, bufsize, "%a, %d %b %Y %H:%M:%S %z", t); 00265 } 00266 setlocale(LC_TIME,oldlocale.c_str()); 00267 result = String(timebuffer); 00268 break; 00269 case ToLocaleString: 00270 strftime(timebuffer, bufsize, cFormat, t); 00271 result = String(timebuffer); 00272 break; 00273 case ToLocaleDateString: 00274 strftime(timebuffer, bufsize, xFormat, t); 00275 result = String(timebuffer); 00276 break; 00277 case ToLocaleTimeString: 00278 strftime(timebuffer, bufsize, "%X", t); 00279 result = String(timebuffer); 00280 break; 00281 case ValueOf: 00282 result = Number(milli); 00283 break; 00284 case GetTime: 00285 result = Number(milli); 00286 break; 00287 case GetYear: 00288 // IE returns the full year even in getYear. 00289 if ( exec->interpreter()->compatMode() != Interpreter::IECompat ) 00290 result = Number(t->tm_year); 00291 else 00292 result = Number(1900 + t->tm_year); 00293 break; 00294 case GetFullYear: 00295 result = Number(1900 + t->tm_year); 00296 break; 00297 case GetMonth: 00298 result = Number(t->tm_mon); 00299 break; 00300 case GetDate: 00301 result = Number(t->tm_mday); 00302 break; 00303 case GetDay: 00304 result = Number(t->tm_wday); 00305 break; 00306 case GetHours: 00307 result = Number(t->tm_hour); 00308 break; 00309 case GetMinutes: 00310 result = Number(t->tm_min); 00311 break; 00312 case GetSeconds: 00313 result = Number(t->tm_sec); 00314 break; 00315 case GetMilliSeconds: 00316 result = Number(ms); 00317 break; 00318 case GetTimezoneOffset: 00319 #if defined BSD || defined(__APPLE__) 00320 result = Number(-(t->tm_gmtoff / 60) + (t->tm_isdst > 0 ? 60 : 0)); 00321 #else 00322 # if defined(__BORLANDC__) 00323 #error please add daylight savings offset here! 00324 result = Number(_timezone / 60 - (t->tm_isdst > 0 ? 60 : 0)); 00325 # else 00326 result = Number((timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 ))); 00327 # endif 00328 #endif 00329 break; 00330 case SetTime: 00331 milli = roundValue(exec,args[0]); 00332 result = Number(milli); 00333 thisObj.setInternalValue(result); 00334 break; 00335 case SetMilliSeconds: 00336 ms = args[0].toInt32(exec); 00337 break; 00338 case SetSeconds: 00339 t->tm_sec = args[0].toInt32(exec); 00340 if (args.size() >= 2) 00341 ms = args[1].toInt32(exec); 00342 break; 00343 case SetMinutes: 00344 t->tm_min = args[0].toInt32(exec); 00345 if (args.size() >= 2) 00346 t->tm_sec = args[1].toInt32(exec); 00347 if (args.size() >= 3) 00348 ms = args[2].toInt32(exec); 00349 break; 00350 case SetHours: 00351 t->tm_hour = args[0].toInt32(exec); 00352 if (args.size() >= 2) 00353 t->tm_min = args[1].toInt32(exec); 00354 if (args.size() >= 3) 00355 t->tm_sec = args[2].toInt32(exec); 00356 if (args.size() >= 4) 00357 ms = args[3].toInt32(exec); 00358 break; 00359 case SetDate: 00360 t->tm_mday = args[0].toInt32(exec); 00361 break; 00362 case SetMonth: 00363 t->tm_mon = args[0].toInt32(exec); 00364 if (args.size() >= 2) 00365 t->tm_mday = args[1].toInt32(exec); 00366 break; 00367 case SetFullYear: 00368 t->tm_year = args[0].toInt32(exec) - 1900; 00369 if (args.size() >= 2) 00370 t->tm_mon = args[1].toInt32(exec); 00371 if (args.size() >= 3) 00372 t->tm_mday = args[2].toInt32(exec); 00373 break; 00374 case SetYear: 00375 t->tm_year = args[0].toInt32(exec) >= 1900 ? args[0].toInt32(exec) - 1900 : args[0].toInt32(exec); 00376 break; 00377 } 00378 00379 if (id == SetYear || id == SetMilliSeconds || id == SetSeconds || 00380 id == SetMinutes || id == SetHours || id == SetDate || 00381 id == SetMonth || id == SetFullYear ) { 00382 t->tm_isdst = -1; // reset DST 00383 result = Number(mktime(t) * 1000.0 + ms); 00384 thisObj.setInternalValue(result); 00385 } 00386 00387 return result; 00388 } 00389 00390 // ------------------------------ DateObjectImp -------------------------------- 00391 00392 // TODO: MakeTime (15.9.11.1) etc. ? 00393 00394 DateObjectImp::DateObjectImp(ExecState *exec, 00395 FunctionPrototypeImp *funcProto, 00396 DatePrototypeImp *dateProto) 00397 : InternalFunctionImp(funcProto) 00398 { 00399 Value protect(this); 00400 00401 // ECMA 15.9.4.1 Date.prototype 00402 putDirect(prototypePropertyName, dateProto, DontEnum|DontDelete|ReadOnly); 00403 00404 static const Identifier parsePropertyName("parse"); 00405 putDirect(parsePropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1), DontEnum); 00406 static const Identifier UTCPropertyName("UTC"); 00407 putDirect(UTCPropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7), DontEnum); 00408 00409 // no. of arguments for constructor 00410 putDirect(lengthPropertyName, 7, ReadOnly|DontDelete|DontEnum); 00411 } 00412 00413 bool DateObjectImp::implementsConstruct() const 00414 { 00415 return true; 00416 } 00417 00418 // ECMA 15.9.3 00419 Object DateObjectImp::construct(ExecState *exec, const List &args) 00420 { 00421 int numArgs = args.size(); 00422 00423 #ifdef KJS_VERBOSE 00424 fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs); 00425 #endif 00426 Value value; 00427 00428 if (numArgs == 0) { // new Date() ECMA 15.9.3.3 00429 #if HAVE_SYS_TIMEB_H 00430 # if defined(__BORLANDC__) 00431 struct timeb timebuffer; 00432 ftime(&timebuffer); 00433 # else 00434 struct _timeb timebuffer; 00435 _ftime(&timebuffer); 00436 # endif 00437 double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm); 00438 #else 00439 struct timeval tv; 00440 gettimeofday(&tv, 0L); 00441 double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0); 00442 #endif 00443 value = Number(utc); 00444 } else if (numArgs == 1) { 00445 UString s = args[0].toString(exec); 00446 double d = s.toDouble(); 00447 if (isNaN(d)) 00448 value = parseDate(s); 00449 else 00450 value = Number(d); 00451 } else { 00452 struct tm t; 00453 memset(&t, 0, sizeof(t)); 00454 int year = args[0].toInt32(exec); 00455 // TODO: check for NaN 00456 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900; 00457 t.tm_mon = args[1].toInt32(exec); 00458 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1; 00459 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0; 00460 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0; 00461 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0; 00462 t.tm_isdst = -1; 00463 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0; 00464 value = Number(mktime(&t) * 1000.0 + ms); 00465 } 00466 00467 Object proto = exec->interpreter()->builtinDatePrototype(); 00468 Object ret(new DateInstanceImp(proto.imp())); 00469 ret.setInternalValue(timeClip(value)); 00470 return ret; 00471 } 00472 00473 bool DateObjectImp::implementsCall() const 00474 { 00475 return true; 00476 } 00477 00478 // ECMA 15.9.2 00479 Value DateObjectImp::call(ExecState* /*exec*/, Object &/*thisObj*/, const List &/*args*/) 00480 { 00481 #ifdef KJS_VERBOSE 00482 fprintf(stderr,"DateObjectImp::call - current time\n"); 00483 #endif 00484 time_t t = time(0L); 00485 UString s(ctime(&t)); 00486 00487 // return formatted string minus trailing \n 00488 return String(s.substr(0, s.size() - 1)); 00489 } 00490 00491 // ------------------------------ DateObjectFuncImp ---------------------------- 00492 00493 DateObjectFuncImp::DateObjectFuncImp(ExecState* /*exec*/, FunctionPrototypeImp *funcProto, 00494 int i, int len) 00495 : InternalFunctionImp(funcProto), id(i) 00496 { 00497 Value protect(this); 00498 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum); 00499 } 00500 00501 bool DateObjectFuncImp::implementsCall() const 00502 { 00503 return true; 00504 } 00505 00506 // ECMA 15.9.4.2 - 3 00507 Value DateObjectFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 00508 { 00509 if (id == Parse) { 00510 return parseDate(args[0].toString(exec)); 00511 } else { // UTC 00512 struct tm t; 00513 memset(&t, 0, sizeof(t)); 00514 int n = args.size(); 00515 int year = args[0].toInt32(exec); 00516 // TODO: check for NaN 00517 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900; 00518 t.tm_mon = args[1].toInt32(exec); 00519 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1; 00520 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0; 00521 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0; 00522 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0; 00523 int ms = (n >= 7) ? args[6].toInt32(exec) : 0; 00524 return Number(mktime(&t) * 1000.0 + ms); 00525 } 00526 } 00527 00528 // ----------------------------------------------------------------------------- 00529 00530 00531 Value KJS::parseDate(const UString &u) 00532 { 00533 #ifdef KJS_VERBOSE 00534 fprintf(stderr,"KJS::parseDate %s\n",u.ascii()); 00535 #endif 00536 double /*time_t*/ seconds = KRFCDate_parseDate( u ); 00537 #ifdef KJS_VERBOSE 00538 fprintf(stderr,"KRFCDate_parseDate returned seconds=%g\n",seconds); 00539 bool withinLimits = true; 00540 if ( sizeof(time_t) == 4 ) 00541 { 00542 int limit = ((time_t)-1 < 0) ? 2038 : 2115; 00543 if ( seconds > (limit-1970) * 365.25 * 86400 ) { 00544 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(seconds/(365.25*86400)+1970)); 00545 withinLimits = false; 00546 } 00547 } 00548 if ( withinLimits ) { 00549 time_t lsec = (time_t)seconds; 00550 fprintf(stderr, "this is: %s\n", ctime(&lsec)); 00551 } 00552 #endif 00553 00554 return Number(seconds == -1 ? NaN : seconds * 1000.0); 00555 } 00556 00558 00559 static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second) 00560 { 00561 //printf("year=%d month=%d day=%d hour=%d minute=%d second=%d\n", year, mon, day, hour, minute, second); 00562 00563 double ret = (day - 32075) /* days */ 00564 + 1461L * (year + 4800L + (mon - 14) / 12) / 4 00565 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12 00566 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4 00567 - 2440588; 00568 ret = 24*ret + hour; /* hours */ 00569 ret = 60*ret + minute; /* minutes */ 00570 ret = 60*ret + second; /* seconds */ 00571 00572 return ret; 00573 } 00574 00575 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec"; 00576 00577 // we follow the recommendation of rfc2822 to consider all 00578 // obsolete time zones not listed here equivalent to "-0000" 00579 static const struct { 00580 const char tzName[4]; 00581 int tzOffset; 00582 } known_zones[] = { 00583 { "UT", 0 }, 00584 { "GMT", 0 }, 00585 { "EST", -300 }, 00586 { "EDT", -240 }, 00587 { "CST", -360 }, 00588 { "CDT", -300 }, 00589 { "MST", -420 }, 00590 { "MDT", -360 }, 00591 { "PST", -480 }, 00592 { "PDT", -420 }, 00593 { { 0, 0, 0, 0 }, 0 } 00594 }; 00595 00596 int KJS::local_timeoffset() 00597 { 00598 static int local_offset = -1; 00599 00600 if ( local_offset != -1 ) return local_offset; 00601 00602 time_t local = time(0); 00603 struct tm* tm_local = gmtime(&local); 00604 local_offset = local-mktime(tm_local); 00605 if(tm_local->tm_isdst) 00606 local_offset += 3600; 00607 00608 return local_offset; 00609 } 00610 00611 double KJS::KRFCDate_parseDate(const UString &_date) 00612 { 00613 // This parse a date in the form: 00614 // Wednesday, 09-Nov-99 23:12:40 GMT 00615 // or 00616 // Sat, 01-Jan-2000 08:00:00 GMT 00617 // or 00618 // Sat, 01 Jan 2000 08:00:00 GMT 00619 // or 00620 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) 00621 // ### non RFC formats, added for Javascript: 00622 // [Wednesday] January 09 1999 23:12:40 GMT 00623 // [Wednesday] January 09 23:12:40 GMT 1999 00624 // 00625 // We ignore the weekday 00626 // 00627 double result = -1; 00628 int offset = 0; 00629 bool have_tz = false; 00630 char *newPosStr; 00631 const char *dateString = _date.ascii(); 00632 int day = 0; 00633 char monthStr[4]; 00634 int month = -1; // not set yet 00635 int year = 0; 00636 int hour = 0; 00637 int minute = 0; 00638 int second = 0; 00639 bool have_time = false; 00640 00641 // Skip leading space 00642 while(*dateString && isspace(*dateString)) 00643 dateString++; 00644 00645 const char *wordStart = dateString; 00646 // Check contents of first words if not number 00647 while(*dateString && !isdigit(*dateString)) 00648 { 00649 if ( isspace(*dateString) && dateString - wordStart >= 3 ) 00650 { 00651 monthStr[0] = tolower(*wordStart++); 00652 monthStr[1] = tolower(*wordStart++); 00653 monthStr[2] = tolower(*wordStart++); 00654 monthStr[3] = '\0'; 00655 //fprintf(stderr,"KJS::parseDate found word starting with '%s'\n", monthStr); 00656 const char *str = strstr(haystack, monthStr); 00657 if (str) { 00658 int position = str - haystack; 00659 if (position % 3 == 0) { 00660 month = position / 3; // Jan=00, Feb=01, Mar=02, .. 00661 } 00662 } 00663 while(*dateString && isspace(*dateString)) 00664 dateString++; 00665 wordStart = dateString; 00666 } 00667 else 00668 dateString++; 00669 } 00670 00671 while(*dateString && isspace(*dateString)) 00672 dateString++; 00673 00674 if (!*dateString) 00675 return invalidDate; 00676 00677 // ' 09-Nov-99 23:12:40 GMT' 00678 day = strtol(dateString, &newPosStr, 10); 00679 dateString = newPosStr; 00680 00681 if ((day < 1) || (day > 31)) 00682 return invalidDate; 00683 if (!*dateString) 00684 return invalidDate; 00685 00686 if (*dateString == '/' && day <= 12 && month == -1) 00687 { 00688 dateString++; 00689 // This looks like a MM/DD/YYYY date, not an RFC date..... 00690 month = day - 1; // 0-based 00691 day = strtol(dateString, &newPosStr, 10); 00692 dateString = newPosStr; 00693 if (*dateString == '/') 00694 dateString++; 00695 if (!*dateString) 00696 return invalidDate; 00697 //printf("month=%d day=%d dateString=%s\n", month, day, dateString); 00698 } 00699 else 00700 { 00701 if (*dateString == '-') 00702 dateString++; 00703 00704 while(*dateString && isspace(*dateString)) 00705 dateString++; 00706 00707 if (*dateString == ',') 00708 dateString++; 00709 00710 if ( month == -1 ) // not found yet 00711 { 00712 for(int i=0; i < 3;i++) 00713 { 00714 if (!*dateString || (*dateString == '-') || isspace(*dateString)) 00715 return invalidDate; 00716 monthStr[i] = tolower(*dateString++); 00717 } 00718 monthStr[3] = '\0'; 00719 00720 newPosStr = (char*)strstr(haystack, monthStr); 00721 00722 if (!newPosStr || (newPosStr - haystack) % 3 != 0) 00723 return invalidDate; 00724 00725 month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, .. 00726 00727 if ((month < 0) || (month > 11)) 00728 return invalidDate; 00729 00730 while(*dateString && (*dateString != '-') && !isspace(*dateString)) 00731 dateString++; 00732 00733 if (!*dateString) 00734 return invalidDate; 00735 00736 // '-99 23:12:40 GMT' 00737 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString)) 00738 return invalidDate; 00739 dateString++; 00740 } 00741 00742 if ((month < 0) || (month > 11)) 00743 return invalidDate; 00744 } 00745 00746 // '99 23:12:40 GMT' 00747 year = strtol(dateString, &newPosStr, 10); 00748 00749 // Don't fail if the time is missing. 00750 if (*newPosStr) 00751 { 00752 // ' 23:12:40 GMT' 00753 if (!isspace(*newPosStr)) { 00754 if ( *newPosStr == ':' ) // Ah, so there was no year, but the number was the hour 00755 year = -1; 00756 else 00757 return invalidDate; 00758 } else // in the normal case (we parsed the year), advance to the next number 00759 dateString = ++newPosStr; 00760 00761 have_time = true; 00762 hour = strtol(dateString, &newPosStr, 10); 00763 dateString = newPosStr; 00764 00765 if ((hour < 0) || (hour > 23)) 00766 return invalidDate; 00767 00768 if (!*dateString) 00769 return invalidDate; 00770 00771 // ':12:40 GMT' 00772 if (*dateString++ != ':') 00773 return invalidDate; 00774 00775 minute = strtol(dateString, &newPosStr, 10); 00776 dateString = newPosStr; 00777 00778 if ((minute < 0) || (minute > 59)) 00779 return invalidDate; 00780 00781 // ':40 GMT' 00782 if (*dateString && *dateString != ':' && !isspace(*dateString)) 00783 return invalidDate; 00784 00785 // seconds are optional in rfc822 + rfc2822 00786 if (*dateString ==':') { 00787 dateString++; 00788 00789 second = strtol(dateString, &newPosStr, 10); 00790 dateString = newPosStr; 00791 00792 if ((second < 0) || (second > 59)) 00793 return invalidDate; 00794 } 00795 00796 while(*dateString && isspace(*dateString)) 00797 dateString++; 00798 } 00799 else 00800 dateString = newPosStr; 00801 00802 00803 // don't fail if the time zone is missing, some 00804 // broken mail-/news-clients omit the time zone 00805 if (*dateString) { 00806 00807 if ( (dateString[0] == 'G' && dateString[1] == 'M' && dateString[2] == 'T') 00808 || (dateString[0] == 'U' && dateString[1] == 'T' && dateString[2] == 'C') ) 00809 { 00810 dateString += 3; 00811 have_tz = true; 00812 } 00813 00814 while (*dateString && isspace(*dateString)) 00815 ++dateString; 00816 00817 if (strncasecmp(dateString, "GMT", 3) == 0) { 00818 dateString += 3; 00819 } 00820 if ((*dateString == '+') || (*dateString == '-')) { 00821 offset = strtol(dateString, &newPosStr, 10); 00822 dateString = newPosStr; 00823 00824 if ((offset < -9959) || (offset > 9959)) 00825 return invalidDate; 00826 00827 int sgn = (offset < 0)? -1:1; 00828 offset = abs(offset); 00829 if ( *dateString == ':' ) { // GMT+05:00 00830 int offset2 = strtol(dateString, &newPosStr, 10); 00831 dateString = newPosStr; 00832 offset = (offset*60 + offset2)*sgn; 00833 } 00834 else 00835 offset = ((offset / 100)*60 + (offset % 100))*sgn; 00836 have_tz = true; 00837 } else { 00838 for (int i=0; known_zones[i].tzName != 0; i++) { 00839 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { 00840 offset = known_zones[i].tzOffset; 00841 have_tz = true; 00842 break; 00843 } 00844 } 00845 } 00846 } 00847 00848 while(*dateString && isspace(*dateString)) 00849 dateString++; 00850 00851 if ( *dateString && year == -1 ) { 00852 year = strtol(dateString, &newPosStr, 10); 00853 } 00854 00855 // Y2K: Solve 2 digit years 00856 if ((year >= 0) && (year < 50)) 00857 year += 2000; 00858 00859 if ((year >= 50) && (year < 100)) 00860 year += 1900; // Y2K 00861 00862 if ((year < 1900) || (year > 2500)) 00863 return invalidDate; 00864 00865 if (!have_time && !have_tz) { 00866 // fall back to midnight, local timezone 00867 struct tm t; 00868 memset(&t, 0, sizeof(tm)); 00869 t.tm_mday = day; 00870 t.tm_mon = month; 00871 t.tm_year = year - 1900; 00872 t.tm_isdst = -1; 00873 return mktime(&t); 00874 } 00875 00876 if(!have_tz) 00877 offset = local_timeoffset(); 00878 else 00879 offset *= 60; 00880 00881 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second); 00882 00883 // avoid negative time values 00884 if ((offset > 0) && (offset > result)) 00885 offset = 0; 00886 00887 result -= offset; 00888 00889 // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT 00890 // This is so that parse error and valid epoch 0 return values won't 00891 // be the same for sensitive applications... 00892 if (result < 1) result = 1; 00893 00894 return result; 00895 } 00896 00897 00898 Value KJS::timeClip(const Value &t) 00899 { 00900 /* TODO */ 00901 return t; 00902 } 00903
KDE Logo
This file is part of the documentation for kjs Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 10 18:55:17 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003