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(__linux__) || defined(__APPLE__) 00320 result = Number(-(t->tm_gmtoff / 60) ); 00321 #else 00322 # if defined(__BORLANDC__) 00323 // FIXME consider non one-hour DST change 00324 #error please add daylight savings offset here! 00325 result = Number(_timezone / 60 - (t->tm_isdst > 0 ? 60 : 0)); 00326 # else 00327 result = Number((timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 ))); 00328 # endif 00329 #endif 00330 break; 00331 case SetTime: 00332 milli = roundValue(exec,args[0]); 00333 result = Number(milli); 00334 thisObj.setInternalValue(result); 00335 break; 00336 case SetMilliSeconds: 00337 ms = args[0].toInt32(exec); 00338 break; 00339 case SetSeconds: 00340 t->tm_sec = args[0].toInt32(exec); 00341 if (args.size() >= 2) 00342 ms = args[1].toInt32(exec); 00343 break; 00344 case SetMinutes: 00345 t->tm_min = args[0].toInt32(exec); 00346 if (args.size() >= 2) 00347 t->tm_sec = args[1].toInt32(exec); 00348 if (args.size() >= 3) 00349 ms = args[2].toInt32(exec); 00350 break; 00351 case SetHours: 00352 t->tm_hour = args[0].toInt32(exec); 00353 if (args.size() >= 2) 00354 t->tm_min = args[1].toInt32(exec); 00355 if (args.size() >= 3) 00356 t->tm_sec = args[2].toInt32(exec); 00357 if (args.size() >= 4) 00358 ms = args[3].toInt32(exec); 00359 break; 00360 case SetDate: 00361 t->tm_mday = args[0].toInt32(exec); 00362 break; 00363 case SetMonth: 00364 t->tm_mon = args[0].toInt32(exec); 00365 if (args.size() >= 2) 00366 t->tm_mday = args[1].toInt32(exec); 00367 break; 00368 case SetFullYear: 00369 t->tm_year = args[0].toInt32(exec) - 1900; 00370 if (args.size() >= 2) 00371 t->tm_mon = args[1].toInt32(exec); 00372 if (args.size() >= 3) 00373 t->tm_mday = args[2].toInt32(exec); 00374 break; 00375 case SetYear: 00376 t->tm_year = args[0].toInt32(exec) >= 1900 ? args[0].toInt32(exec) - 1900 : args[0].toInt32(exec); 00377 break; 00378 } 00379 00380 if (id == SetYear || id == SetMilliSeconds || id == SetSeconds || 00381 id == SetMinutes || id == SetHours || id == SetDate || 00382 id == SetMonth || id == SetFullYear ) { 00383 result = makeTime(t, ms, utc); 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 = makeTime(&t, ms, false); 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 makeTime(&t, ms, true); 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 Number KJS::makeTime(struct tm *t, int ms, bool utc) 00597 { 00598 int utcOffset; 00599 if (utc) { 00600 time_t zero = 0; 00601 struct tm t3; 00602 localtime_r(&zero, &t3); 00603 #if defined BSD || defined(__linux__) || defined(__APPLE__) 00604 utcOffset = t3.tm_gmtoff; 00605 t->tm_isdst = t3.tm_isdst; 00606 #else 00607 # if defined(__BORLANDC__) 00608 utcOffset = - _timezone; 00609 # else 00610 utcOffset = - timezone; 00611 # endif 00612 t->tm_isdst = 0; 00613 #endif 00614 } else { 00615 utcOffset = 0; 00616 t->tm_isdst = -1; 00617 } 00618 00619 return Number( ( mktime(t) + utcOffset ) * 1000.0 + ms ); 00620 } 00621 00622 double KJS::KRFCDate_parseDate(const UString &_date) 00623 { 00624 // This parse a date in the form: 00625 // Wednesday, 09-Nov-99 23:12:40 GMT 00626 // or 00627 // Sat, 01-Jan-2000 08:00:00 GMT 00628 // or 00629 // Sat, 01 Jan 2000 08:00:00 GMT 00630 // or 00631 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) 00632 // ### non RFC formats, added for Javascript: 00633 // [Wednesday] January 09 1999 23:12:40 GMT 00634 // [Wednesday] January 09 23:12:40 GMT 1999 00635 // 00636 // We ignore the weekday 00637 // 00638 double result = -1; 00639 int offset = 0; 00640 bool have_tz = false; 00641 char *newPosStr; 00642 const char *dateString = _date.ascii(); 00643 int day = 0; 00644 char monthStr[4]; 00645 int month = -1; // not set yet 00646 int year = 0; 00647 int hour = 0; 00648 int minute = 0; 00649 int second = 0; 00650 bool have_time = false; 00651 00652 // Skip leading space 00653 while(*dateString && isspace(*dateString)) 00654 dateString++; 00655 00656 const char *wordStart = dateString; 00657 // Check contents of first words if not number 00658 while(*dateString && !isdigit(*dateString)) 00659 { 00660 if ( isspace(*dateString) && dateString - wordStart >= 3 ) 00661 { 00662 monthStr[0] = tolower(*wordStart++); 00663 monthStr[1] = tolower(*wordStart++); 00664 monthStr[2] = tolower(*wordStart++); 00665 monthStr[3] = '\0'; 00666 //fprintf(stderr,"KJS::parseDate found word starting with '%s'\n", monthStr); 00667 const char *str = strstr(haystack, monthStr); 00668 if (str) { 00669 int position = str - haystack; 00670 if (position % 3 == 0) { 00671 month = position / 3; // Jan=00, Feb=01, Mar=02, .. 00672 } 00673 } 00674 while(*dateString && isspace(*dateString)) 00675 dateString++; 00676 wordStart = dateString; 00677 } 00678 else 00679 dateString++; 00680 } 00681 00682 while(*dateString && isspace(*dateString)) 00683 dateString++; 00684 00685 if (!*dateString) 00686 return invalidDate; 00687 00688 // ' 09-Nov-99 23:12:40 GMT' 00689 day = strtol(dateString, &newPosStr, 10); 00690 dateString = newPosStr; 00691 00692 if (!*dateString) 00693 return invalidDate; 00694 00695 if (day < 1) 00696 return invalidDate; 00697 if (day > 31) { 00698 // ### where is the boundary and what happens below? 00699 if (*dateString == '/' && day >= 1000) { 00700 // looks like a YYYY/MM/DD date 00701 if (!*++dateString) 00702 return invalidDate; 00703 year = day; 00704 month = strtol(dateString, &newPosStr, 10) - 1; 00705 dateString = newPosStr; 00706 if (*dateString++ != '/' || !*dateString) 00707 return invalidDate; 00708 day = strtol(dateString, &newPosStr, 10); 00709 dateString = newPosStr; 00710 } else { 00711 return invalidDate; 00712 } 00713 } else if (*dateString == '/' && day <= 12 && month == -1) 00714 { 00715 dateString++; 00716 // This looks like a MM/DD/YYYY date, not an RFC date..... 00717 month = day - 1; // 0-based 00718 day = strtol(dateString, &newPosStr, 10); 00719 dateString = newPosStr; 00720 if (*dateString == '/') 00721 dateString++; 00722 if (!*dateString) 00723 return invalidDate; 00724 //printf("month=%d day=%d dateString=%s\n", month, day, dateString); 00725 } 00726 else 00727 { 00728 if (*dateString == '-') 00729 dateString++; 00730 00731 while(*dateString && isspace(*dateString)) 00732 dateString++; 00733 00734 if (*dateString == ',') 00735 dateString++; 00736 00737 if ( month == -1 ) // not found yet 00738 { 00739 for(int i=0; i < 3;i++) 00740 { 00741 if (!*dateString || (*dateString == '-') || isspace(*dateString)) 00742 return invalidDate; 00743 monthStr[i] = tolower(*dateString++); 00744 } 00745 monthStr[3] = '\0'; 00746 00747 newPosStr = (char*)strstr(haystack, monthStr); 00748 00749 if (!newPosStr || (newPosStr - haystack) % 3 != 0) 00750 return invalidDate; 00751 00752 month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, .. 00753 00754 if ((month < 0) || (month > 11)) 00755 return invalidDate; 00756 00757 while(*dateString && (*dateString != '-') && !isspace(*dateString)) 00758 dateString++; 00759 00760 if (!*dateString) 00761 return invalidDate; 00762 00763 // '-99 23:12:40 GMT' 00764 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString)) 00765 return invalidDate; 00766 dateString++; 00767 } 00768 00769 if ((month < 0) || (month > 11)) 00770 return invalidDate; 00771 } 00772 00773 // '99 23:12:40 GMT' 00774 if (year <= 0 && *dateString) 00775 year = strtol(dateString, &newPosStr, 10); 00776 00777 // Don't fail if the time is missing. 00778 if (*newPosStr) 00779 { 00780 // ' 23:12:40 GMT' 00781 if (!isspace(*newPosStr)) { 00782 if ( *newPosStr == ':' ) // Ah, so there was no year, but the number was the hour 00783 year = -1; 00784 else 00785 return invalidDate; 00786 } else // in the normal case (we parsed the year), advance to the next number 00787 dateString = ++newPosStr; 00788 00789 have_time = true; 00790 hour = strtol(dateString, &newPosStr, 10); 00791 dateString = newPosStr; 00792 00793 if ((hour < 0) || (hour > 23)) 00794 return invalidDate; 00795 00796 if (!*dateString) 00797 return invalidDate; 00798 00799 // ':12:40 GMT' 00800 if (*dateString++ != ':') 00801 return invalidDate; 00802 00803 minute = strtol(dateString, &newPosStr, 10); 00804 dateString = newPosStr; 00805 00806 if ((minute < 0) || (minute > 59)) 00807 return invalidDate; 00808 00809 // ':40 GMT' 00810 if (*dateString && *dateString != ':' && !isspace(*dateString)) 00811 return invalidDate; 00812 00813 // seconds are optional in rfc822 + rfc2822 00814 if (*dateString ==':') { 00815 dateString++; 00816 00817 second = strtol(dateString, &newPosStr, 10); 00818 dateString = newPosStr; 00819 00820 if ((second < 0) || (second > 59)) 00821 return invalidDate; 00822 } 00823 00824 while(*dateString && isspace(*dateString)) 00825 dateString++; 00826 } 00827 else 00828 dateString = newPosStr; 00829 00830 00831 // don't fail if the time zone is missing, some 00832 // broken mail-/news-clients omit the time zone 00833 if (*dateString) { 00834 00835 if ( (dateString[0] == 'G' && dateString[1] == 'M' && dateString[2] == 'T') 00836 || (dateString[0] == 'U' && dateString[1] == 'T' && dateString[2] == 'C') ) 00837 { 00838 dateString += 3; 00839 have_tz = true; 00840 } 00841 00842 while (*dateString && isspace(*dateString)) 00843 ++dateString; 00844 00845 if (strncasecmp(dateString, "GMT", 3) == 0) { 00846 dateString += 3; 00847 } 00848 if ((*dateString == '+') || (*dateString == '-')) { 00849 offset = strtol(dateString, &newPosStr, 10); 00850 dateString = newPosStr; 00851 00852 if ((offset < -9959) || (offset > 9959)) 00853 return invalidDate; 00854 00855 int sgn = (offset < 0)? -1:1; 00856 offset = abs(offset); 00857 if ( *dateString == ':' ) { // GMT+05:00 00858 int offset2 = strtol(dateString, &newPosStr, 10); 00859 dateString = newPosStr; 00860 offset = (offset*60 + offset2)*sgn; 00861 } 00862 else 00863 offset = ((offset / 100)*60 + (offset % 100))*sgn; 00864 have_tz = true; 00865 } else { 00866 for (int i=0; known_zones[i].tzName != 0; i++) { 00867 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { 00868 offset = known_zones[i].tzOffset; 00869 have_tz = true; 00870 break; 00871 } 00872 } 00873 } 00874 } 00875 00876 while(*dateString && isspace(*dateString)) 00877 dateString++; 00878 00879 if ( *dateString && year == -1 ) { 00880 year = strtol(dateString, &newPosStr, 10); 00881 } 00882 00883 // Y2K: Solve 2 digit years 00884 if ((year >= 0) && (year < 50)) 00885 year += 2000; 00886 00887 if ((year >= 50) && (year < 100)) 00888 year += 1900; // Y2K 00889 00890 if ((year < 1900) || (year > 2500)) 00891 return invalidDate; 00892 00893 if (!have_tz) { 00894 // fall back to midnight, local timezone 00895 struct tm t; 00896 memset(&t, 0, sizeof(tm)); 00897 t.tm_mday = day; 00898 t.tm_mon = month; 00899 t.tm_year = year - 1900; 00900 t.tm_isdst = -1; 00901 if (have_time) { 00902 t.tm_sec = second; 00903 t.tm_min = minute; 00904 t.tm_hour = hour; 00905 } 00906 00907 return mktime(&t); 00908 } 00909 00910 offset *= 60; 00911 00912 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second); 00913 00914 // avoid negative time values 00915 if ((offset > 0) && (offset > result)) 00916 offset = 0; 00917 00918 result -= offset; 00919 00920 // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT 00921 // This is so that parse error and valid epoch 0 return values won't 00922 // be the same for sensitive applications... 00923 if (result < 1) result = 1; 00924 00925 return result; 00926 } 00927 00928 00929 Value KJS::timeClip(const Value &t) 00930 { 00931 /* TODO */ 00932 return t; 00933 } 00934
KDE Logo
This file is part of the documentation for kjs Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:28:45 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003