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