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 result = Number(mktime(t) * 1000.0 + ms); 00383 thisObj.setInternalValue(result); 00384 } 00385 00386 return result; 00387 } 00388 00389 // ------------------------------ DateObjectImp -------------------------------- 00390 00391 // TODO: MakeTime (15.9.11.1) etc. ? 00392 00393 DateObjectImp::DateObjectImp(ExecState *exec, 00394 FunctionPrototypeImp *funcProto, 00395 DatePrototypeImp *dateProto) 00396 : InternalFunctionImp(funcProto) 00397 { 00398 Value protect(this); 00399 00400 // ECMA 15.9.4.1 Date.prototype 00401 putDirect(prototypePropertyName, dateProto, DontEnum|DontDelete|ReadOnly); 00402 00403 static const Identifier parsePropertyName("parse"); 00404 putDirect(parsePropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1), DontEnum); 00405 static const Identifier UTCPropertyName("UTC"); 00406 putDirect(UTCPropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7), DontEnum); 00407 00408 // no. of arguments for constructor 00409 putDirect(lengthPropertyName, 7, ReadOnly|DontDelete|DontEnum); 00410 } 00411 00412 bool DateObjectImp::implementsConstruct() const 00413 { 00414 return true; 00415 } 00416 00417 // ECMA 15.9.3 00418 Object DateObjectImp::construct(ExecState *exec, const List &args) 00419 { 00420 int numArgs = args.size(); 00421 00422 #ifdef KJS_VERBOSE 00423 fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs); 00424 #endif 00425 Value value; 00426 00427 if (numArgs == 0) { // new Date() ECMA 15.9.3.3 00428 #if HAVE_SYS_TIMEB_H 00429 # if defined(__BORLANDC__) 00430 struct timeb timebuffer; 00431 ftime(&timebuffer); 00432 # else 00433 struct _timeb timebuffer; 00434 _ftime(&timebuffer); 00435 # endif 00436 double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm); 00437 #else 00438 struct timeval tv; 00439 gettimeofday(&tv, 0L); 00440 double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0); 00441 #endif 00442 value = Number(utc); 00443 } else if (numArgs == 1) { 00444 UString s = args[0].toString(exec); 00445 double d = s.toDouble(); 00446 if (isNaN(d)) 00447 value = parseDate(s); 00448 else 00449 value = Number(d); 00450 } else { 00451 struct tm t; 00452 memset(&t, 0, sizeof(t)); 00453 int year = args[0].toInt32(exec); 00454 // TODO: check for NaN 00455 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900; 00456 t.tm_mon = args[1].toInt32(exec); 00457 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1; 00458 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0; 00459 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0; 00460 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0; 00461 t.tm_isdst = -1; 00462 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0; 00463 value = Number(mktime(&t) * 1000.0 + ms); 00464 } 00465 00466 Object proto = exec->interpreter()->builtinDatePrototype(); 00467 Object ret(new DateInstanceImp(proto.imp())); 00468 ret.setInternalValue(timeClip(value)); 00469 return ret; 00470 } 00471 00472 bool DateObjectImp::implementsCall() const 00473 { 00474 return true; 00475 } 00476 00477 // ECMA 15.9.2 00478 Value DateObjectImp::call(ExecState* /*exec*/, Object &/*thisObj*/, const List &/*args*/) 00479 { 00480 #ifdef KJS_VERBOSE 00481 fprintf(stderr,"DateObjectImp::call - current time\n"); 00482 #endif 00483 time_t t = time(0L); 00484 UString s(ctime(&t)); 00485 00486 // return formatted string minus trailing \n 00487 return String(s.substr(0, s.size() - 1)); 00488 } 00489 00490 // ------------------------------ DateObjectFuncImp ---------------------------- 00491 00492 DateObjectFuncImp::DateObjectFuncImp(ExecState* /*exec*/, FunctionPrototypeImp *funcProto, 00493 int i, int len) 00494 : InternalFunctionImp(funcProto), id(i) 00495 { 00496 Value protect(this); 00497 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum); 00498 } 00499 00500 bool DateObjectFuncImp::implementsCall() const 00501 { 00502 return true; 00503 } 00504 00505 // ECMA 15.9.4.2 - 3 00506 Value DateObjectFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 00507 { 00508 if (id == Parse) { 00509 return parseDate(args[0].toString(exec)); 00510 } else { // UTC 00511 struct tm t; 00512 memset(&t, 0, sizeof(t)); 00513 int n = args.size(); 00514 int year = args[0].toInt32(exec); 00515 // TODO: check for NaN 00516 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900; 00517 t.tm_mon = args[1].toInt32(exec); 00518 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1; 00519 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0; 00520 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0; 00521 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0; 00522 int ms = (n >= 7) ? args[6].toInt32(exec) : 0; 00523 return Number(mktime(&t) * 1000.0 + ms); 00524 } 00525 } 00526 00527 // ----------------------------------------------------------------------------- 00528 00529 00530 Value KJS::parseDate(const UString &u) 00531 { 00532 #ifdef KJS_VERBOSE 00533 fprintf(stderr,"KJS::parseDate %s\n",u.ascii()); 00534 #endif 00535 double /*time_t*/ seconds = KRFCDate_parseDate( u ); 00536 #ifdef KJS_VERBOSE 00537 fprintf(stderr,"KRFCDate_parseDate returned seconds=%g\n",seconds); 00538 bool withinLimits = true; 00539 if ( sizeof(time_t) == 4 ) 00540 { 00541 int limit = ((time_t)-1 < 0) ? 2038 : 2115; 00542 if ( seconds > (limit-1970) * 365.25 * 86400 ) { 00543 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(seconds/(365.25*86400)+1970)); 00544 withinLimits = false; 00545 } 00546 } 00547 if ( withinLimits ) { 00548 time_t lsec = (time_t)seconds; 00549 fprintf(stderr, "this is: %s\n", ctime(&lsec)); 00550 } 00551 #endif 00552 00553 return Number(seconds == -1 ? NaN : seconds * 1000.0); 00554 } 00555 00557 00558 static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second) 00559 { 00560 //printf("year=%d month=%d day=%d hour=%d minute=%d second=%d\n", year, mon, day, hour, minute, second); 00561 00562 double ret = (day - 32075) /* days */ 00563 + 1461L * (year + 4800L + (mon - 14) / 12) / 4 00564 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12 00565 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4 00566 - 2440588; 00567 ret = 24*ret + hour; /* hours */ 00568 ret = 60*ret + minute; /* minutes */ 00569 ret = 60*ret + second; /* seconds */ 00570 00571 return ret; 00572 } 00573 00574 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec"; 00575 00576 // we follow the recommendation of rfc2822 to consider all 00577 // obsolete time zones not listed here equivalent to "-0000" 00578 static const struct { 00579 const char tzName[4]; 00580 int tzOffset; 00581 } known_zones[] = { 00582 { "UT", 0 }, 00583 { "GMT", 0 }, 00584 { "EST", -300 }, 00585 { "EDT", -240 }, 00586 { "CST", -360 }, 00587 { "CDT", -300 }, 00588 { "MST", -420 }, 00589 { "MDT", -360 }, 00590 { "PST", -480 }, 00591 { "PDT", -420 }, 00592 { { 0, 0, 0, 0 }, 0 } 00593 }; 00594 00595 int KJS::local_timeoffset() 00596 { 00597 static int local_offset = -1; 00598 00599 if ( local_offset != -1 ) return local_offset; 00600 00601 time_t local = time(0); 00602 struct tm* tm_local = gmtime(&local); 00603 local_offset = local-mktime(tm_local); 00604 if(tm_local->tm_isdst) 00605 local_offset += 3600; 00606 00607 return local_offset; 00608 } 00609 00610 double KJS::KRFCDate_parseDate(const UString &_date) 00611 { 00612 // This parse a date in the form: 00613 // Wednesday, 09-Nov-99 23:12:40 GMT 00614 // or 00615 // Sat, 01-Jan-2000 08:00:00 GMT 00616 // or 00617 // Sat, 01 Jan 2000 08:00:00 GMT 00618 // or 00619 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) 00620 // ### non RFC formats, added for Javascript: 00621 // [Wednesday] January 09 1999 23:12:40 GMT 00622 // [Wednesday] January 09 23:12:40 GMT 1999 00623 // 00624 // We ignore the weekday 00625 // 00626 double result = -1; 00627 int offset = 0; 00628 bool have_tz = false; 00629 char *newPosStr; 00630 const char *dateString = _date.ascii(); 00631 int day = 0; 00632 char monthStr[4]; 00633 int month = -1; // not set yet 00634 int year = 0; 00635 int hour = 0; 00636 int minute = 0; 00637 int second = 0; 00638 bool have_time = false; 00639 00640 // Skip leading space 00641 while(*dateString && isspace(*dateString)) 00642 dateString++; 00643 00644 const char *wordStart = dateString; 00645 // Check contents of first words if not number 00646 while(*dateString && !isdigit(*dateString)) 00647 { 00648 if ( isspace(*dateString) && dateString - wordStart >= 3 ) 00649 { 00650 monthStr[0] = tolower(*wordStart++); 00651 monthStr[1] = tolower(*wordStart++); 00652 monthStr[2] = tolower(*wordStart++); 00653 monthStr[3] = '\0'; 00654 //fprintf(stderr,"KJS::parseDate found word starting with '%s'\n", monthStr); 00655 const char *str = strstr(haystack, monthStr); 00656 if (str) { 00657 int position = str - haystack; 00658 if (position % 3 == 0) { 00659 month = position / 3; // Jan=00, Feb=01, Mar=02, .. 00660 } 00661 } 00662 while(*dateString && isspace(*dateString)) 00663 dateString++; 00664 wordStart = dateString; 00665 } 00666 else 00667 dateString++; 00668 } 00669 00670 while(*dateString && isspace(*dateString)) 00671 dateString++; 00672 00673 if (!*dateString) 00674 return invalidDate; 00675 00676 // ' 09-Nov-99 23:12:40 GMT' 00677 day = strtol(dateString, &newPosStr, 10); 00678 dateString = newPosStr; 00679 00680 if ((day < 1) || (day > 31)) 00681 return invalidDate; 00682 if (!*dateString) 00683 return invalidDate; 00684 00685 if (*dateString == '/' && day <= 12 && month == -1) 00686 { 00687 dateString++; 00688 // This looks like a MM/DD/YYYY date, not an RFC date..... 00689 month = day - 1; // 0-based 00690 day = strtol(dateString, &newPosStr, 10); 00691 dateString = newPosStr; 00692 if (*dateString == '/') 00693 dateString++; 00694 if (!*dateString) 00695 return invalidDate; 00696 //printf("month=%d day=%d dateString=%s\n", month, day, dateString); 00697 } 00698 else 00699 { 00700 if (*dateString == '-') 00701 dateString++; 00702 00703 while(*dateString && isspace(*dateString)) 00704 dateString++; 00705 00706 if (*dateString == ',') 00707 dateString++; 00708 00709 if ( month == -1 ) // not found yet 00710 { 00711 for(int i=0; i < 3;i++) 00712 { 00713 if (!*dateString || (*dateString == '-') || isspace(*dateString)) 00714 return invalidDate; 00715 monthStr[i] = tolower(*dateString++); 00716 } 00717 monthStr[3] = '\0'; 00718 00719 newPosStr = (char*)strstr(haystack, monthStr); 00720 00721 if (!newPosStr || (newPosStr - haystack) % 3 != 0) 00722 return invalidDate; 00723 00724 month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, .. 00725 00726 if ((month < 0) || (month > 11)) 00727 return invalidDate; 00728 00729 while(*dateString && (*dateString != '-') && !isspace(*dateString)) 00730 dateString++; 00731 00732 if (!*dateString) 00733 return invalidDate; 00734 00735 // '-99 23:12:40 GMT' 00736 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString)) 00737 return invalidDate; 00738 dateString++; 00739 } 00740 00741 if ((month < 0) || (month > 11)) 00742 return invalidDate; 00743 } 00744 00745 // '99 23:12:40 GMT' 00746 year = strtol(dateString, &newPosStr, 10); 00747 00748 // Don't fail if the time is missing. 00749 if (*newPosStr) 00750 { 00751 // ' 23:12:40 GMT' 00752 if (!isspace(*newPosStr)) { 00753 if ( *newPosStr == ':' ) // Ah, so there was no year, but the number was the hour 00754 year = -1; 00755 else 00756 return invalidDate; 00757 } else // in the normal case (we parsed the year), advance to the next number 00758 dateString = ++newPosStr; 00759 00760 have_time = true; 00761 hour = strtol(dateString, &newPosStr, 10); 00762 dateString = newPosStr; 00763 00764 if ((hour < 0) || (hour > 23)) 00765 return invalidDate; 00766 00767 if (!*dateString) 00768 return invalidDate; 00769 00770 // ':12:40 GMT' 00771 if (*dateString++ != ':') 00772 return invalidDate; 00773 00774 minute = strtol(dateString, &newPosStr, 10); 00775 dateString = newPosStr; 00776 00777 if ((minute < 0) || (minute > 59)) 00778 return invalidDate; 00779 00780 // ':40 GMT' 00781 if (*dateString && *dateString != ':' && !isspace(*dateString)) 00782 return invalidDate; 00783 00784 // seconds are optional in rfc822 + rfc2822 00785 if (*dateString ==':') { 00786 dateString++; 00787 00788 second = strtol(dateString, &newPosStr, 10); 00789 dateString = newPosStr; 00790 00791 if ((second < 0) || (second > 59)) 00792 return invalidDate; 00793 } 00794 00795 while(*dateString && isspace(*dateString)) 00796 dateString++; 00797 } 00798 else 00799 dateString = newPosStr; 00800 00801 00802 // don't fail if the time zone is missing, some 00803 // broken mail-/news-clients omit the time zone 00804 if (*dateString) { 00805 00806 if ( (dateString[0] == 'G' && dateString[1] == 'M' && dateString[2] == 'T') 00807 || (dateString[0] == 'U' && dateString[1] == 'T' && dateString[2] == 'C') ) 00808 { 00809 dateString += 3; 00810 have_tz = true; 00811 } 00812 00813 while (*dateString && isspace(*dateString)) 00814 ++dateString; 00815 00816 if (strncasecmp(dateString, "GMT", 3) == 0) { 00817 dateString += 3; 00818 } 00819 if ((*dateString == '+') || (*dateString == '-')) { 00820 offset = strtol(dateString, &newPosStr, 10); 00821 dateString = newPosStr; 00822 00823 if ((offset < -9959) || (offset > 9959)) 00824 return invalidDate; 00825 00826 int sgn = (offset < 0)? -1:1; 00827 offset = abs(offset); 00828 if ( *dateString == ':' ) { // GMT+05:00 00829 int offset2 = strtol(dateString, &newPosStr, 10); 00830 dateString = newPosStr; 00831 offset = (offset*60 + offset2)*sgn; 00832 } 00833 else 00834 offset = ((offset / 100)*60 + (offset % 100))*sgn; 00835 have_tz = true; 00836 } else { 00837 for (int i=0; known_zones[i].tzName != 0; i++) { 00838 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { 00839 offset = known_zones[i].tzOffset; 00840 have_tz = true; 00841 break; 00842 } 00843 } 00844 } 00845 } 00846 00847 while(*dateString && isspace(*dateString)) 00848 dateString++; 00849 00850 if ( *dateString && year == -1 ) { 00851 year = strtol(dateString, &newPosStr, 10); 00852 } 00853 00854 // Y2K: Solve 2 digit years 00855 if ((year >= 0) && (year < 50)) 00856 year += 2000; 00857 00858 if ((year >= 50) && (year < 100)) 00859 year += 1900; // Y2K 00860 00861 if ((year < 1900) || (year > 2500)) 00862 return invalidDate; 00863 00864 if (!have_time && !have_tz) { 00865 // fall back to midnight, local timezone 00866 struct tm t; 00867 memset(&t, 0, sizeof(tm)); 00868 t.tm_mday = day; 00869 t.tm_mon = month; 00870 t.tm_year = year - 1900; 00871 t.tm_isdst = -1; 00872 return mktime(&t); 00873 } 00874 00875 if(!have_tz) 00876 offset = local_timeoffset(); 00877 else 00878 offset *= 60; 00879 00880 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second); 00881 00882 // avoid negative time values 00883 if ((offset > 0) && (offset > result)) 00884 offset = 0; 00885 00886 result -= offset; 00887 00888 // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT 00889 // This is so that parse error and valid epoch 0 return values won't 00890 // be the same for sensitive applications... 00891 if (result < 1) result = 1; 00892 00893 return result; 00894 } 00895 00896 00897 Value KJS::timeClip(const Value &t) 00898 { 00899 /* TODO */ 00900 return t; 00901 } 00902
KDE Logo
This file is part of the documentation for kjs Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:39 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003