date_object.cpp Source File (kjs Library)

| # kjs Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:08:18 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001