00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #if TIME_WITH_SYS_TIME
00028 # include <sys/time.h>
00029 # include <time.h>
00030 #else
00031 #if HAVE_SYS_TIME_H
00032 #include <sys/time.h>
00033 #else
00034 # include <time.h>
00035 # endif
00036 #endif
00037 #ifdef HAVE_SYS_TIMEB_H
00038 #include <sys/timeb.h>
00039 #endif
00040
00041 #ifdef HAVE_SYS_PARAM_H
00042 # include <sys/param.h>
00043 #endif // HAVE_SYS_PARAM_H
00044
00045 #include <math.h>
00046 #include <string.h>
00047 #ifdef HAVE_STRINGS_H
00048 # include <strings.h>
00049 #endif
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <locale.h>
00053 #include <ctype.h>
00054 #include <assert.h>
00055
00056 #include "date_object.h"
00057 #include "error_object.h"
00058 #include "operations.h"
00059
00060 #include "date_object.lut.h"
00061
00062 using namespace KJS;
00063
00064
00065 const time_t invalidDate = -1;
00066 const double hoursPerDay = 24;
00067 const double minutesPerHour = 60;
00068 const double secondsPerMinute = 60;
00069 const double msPerSecond = 1000;
00070 const double msPerMinute = msPerSecond * secondsPerMinute;
00071 const double msPerHour = msPerMinute * minutesPerHour;
00072 const double msPerDay = msPerHour * hoursPerDay;
00073
00074 static int day(double t)
00075 {
00076 return int(floor(t / msPerDay));
00077 }
00078
00079 static double dayFromYear(int year)
00080 {
00081 return 365.0 * (year - 1970)
00082 + floor((year - 1969) / 4.0)
00083 - floor((year - 1901) / 100.0)
00084 + floor((year - 1601) / 400.0);
00085 }
00086
00087
00088 static int daysInYear(int year)
00089 {
00090 if (year % 4 != 0)
00091 return 365;
00092 else if (year % 400 == 0)
00093 return 366;
00094 else if (year % 100 == 0)
00095 return 365;
00096 else
00097 return 366;
00098 }
00099
00100
00101 double timeFromYear(int year)
00102 {
00103 return msPerDay * dayFromYear(year);
00104 }
00105
00106
00107 int yearFromTime(double t)
00108 {
00109
00110
00111 int y = 1970 + int(t / (365.25 * msPerDay));
00112
00113 if (timeFromYear(y) > t) {
00114 do {
00115 --y;
00116 } while (timeFromYear(y) > t);
00117 } else {
00118 while (timeFromYear(y + 1) < t)
00119 ++y;
00120 }
00121
00122 return y;
00123 }
00124
00125
00126 int weekDay(double t)
00127 {
00128 int wd = (day(t) + 4) % 7;
00129 if (wd < 0)
00130 wd += 7;
00131 return wd;
00132 }
00133
00134 static double timeZoneOffset(const struct tm *t)
00135 {
00136 #if defined BSD || defined(__linux__) || defined(__APPLE__)
00137 return -(t->tm_gmtoff / 60);
00138 #else
00139 # if defined(__BORLANDC__)
00140
00141 #error please add daylight savings offset here!
00142 return _timezone / 60 - (t->tm_isdst > 0 ? 60 : 0);
00143 # else
00144 return timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 );
00145 # endif
00146 #endif
00147 }
00148
00149
00150
00151 const ClassInfo DateInstanceImp::info = {"Date", 0, 0, 0};
00152
00153 DateInstanceImp::DateInstanceImp(ObjectImp *proto)
00154 : ObjectImp(proto)
00155 {
00156 }
00157
00158
00159
00160 const ClassInfo DatePrototypeImp::info = {"Date", 0, &dateTable, 0};
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 DatePrototypeImp::DatePrototypeImp(ExecState *,
00215 ObjectPrototypeImp *objectProto)
00216 : DateInstanceImp(objectProto)
00217 {
00218 Value protect(this);
00219 setInternalValue(Number(NaN));
00220
00221 }
00222
00223 Value DatePrototypeImp::get(ExecState *exec, const Identifier &propertyName) const
00224 {
00225 return lookupGetFunction<DateProtoFuncImp, ObjectImp>( exec, propertyName, &dateTable, this );
00226 }
00227
00228
00229
00230 DateProtoFuncImp::DateProtoFuncImp(ExecState *exec, int i, int len)
00231 : InternalFunctionImp(
00232 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
00233 ), id(abs(i)), utc(i<0)
00234
00235 {
00236 Value protect(this);
00237 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00238 }
00239
00240 bool DateProtoFuncImp::implementsCall() const
00241 {
00242 return true;
00243 }
00244
00245 Value DateProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00246 {
00247 if ((id == ToString || id == ValueOf || id == GetTime || id == SetTime) &&
00248 !thisObj.inherits(&DateInstanceImp::info)) {
00249
00250
00251
00252
00253 Object err = Error::create(exec,TypeError);
00254 exec->setException(err);
00255 return err;
00256 }
00257
00258
00259 Value result;
00260 UString s;
00261 const int bufsize=100;
00262 char timebuffer[bufsize];
00263 CString oldlocale = setlocale(LC_TIME,NULL);
00264 if (!oldlocale.c_str())
00265 oldlocale = setlocale(LC_ALL, NULL);
00266 Value v = thisObj.internalValue();
00267 double milli = v.toNumber(exec);
00268
00269 if (isNaN(milli)) {
00270 switch (id) {
00271 case ToString:
00272 case ToDateString:
00273 case ToTimeString:
00274 case ToGMTString:
00275 case ToUTCString:
00276 case ToLocaleString:
00277 case ToLocaleDateString:
00278 case ToLocaleTimeString:
00279 return String("Invalid Date");
00280 case ValueOf:
00281 case GetTime:
00282 case GetYear:
00283 case GetFullYear:
00284 case GetMonth:
00285 case GetDate:
00286 case GetDay:
00287 case GetHours:
00288 case GetMinutes:
00289 case GetSeconds:
00290 case GetMilliSeconds:
00291 case GetTimezoneOffset:
00292 return Number(NaN);
00293 }
00294 }
00295
00296
00297
00298 int realYearOffset = 0;
00299 double milliOffset = 0.0;
00300 if (milli < 0 || milli >= timeFromYear(2038)) {
00301
00302 int realYear = yearFromTime(milli);
00303 int base = daysInYear(realYear) == 365 ? 2001 : 2000;
00304 milliOffset = timeFromYear(base) - timeFromYear(realYear);
00305 milli += milliOffset;
00306 realYearOffset = realYear - base;
00307 }
00308
00309 time_t tv = (time_t) floor(milli / 1000.0);
00310 int ms = int(milli - tv * 1000.0);
00311
00312 struct tm *t;
00313 if ( (id == DateProtoFuncImp::ToGMTString) ||
00314 (id == DateProtoFuncImp::ToUTCString) )
00315 t = gmtime(&tv);
00316 else if (id == DateProtoFuncImp::ToString)
00317 t = localtime(&tv);
00318 else if (utc)
00319 t = gmtime(&tv);
00320 else
00321 t = localtime(&tv);
00322
00323
00324
00325 if (realYearOffset != 0) {
00326 t->tm_year += realYearOffset;
00327 milli -= milliOffset;
00328
00329 double m = milli;
00330 if (!utc)
00331 m -= timeZoneOffset(t) * msPerMinute;
00332 t->tm_wday = weekDay(m);
00333 }
00334
00335
00336 const char xFormat[] = "%x";
00337 const char cFormat[] = "%c";
00338
00339 switch (id) {
00340 case ToString:
00341 case ToDateString:
00342 case ToTimeString:
00343 case ToGMTString:
00344 case ToUTCString:
00345 setlocale(LC_TIME,"C");
00346 if (id == DateProtoFuncImp::ToDateString) {
00347 strftime(timebuffer, bufsize, xFormat, t);
00348 } else if (id == DateProtoFuncImp::ToTimeString) {
00349 strftime(timebuffer, bufsize, "%X",t);
00350 } else {
00351 strftime(timebuffer, bufsize, "%a, %d %b %Y %H:%M:%S %z", t);
00352 }
00353 setlocale(LC_TIME,oldlocale.c_str());
00354 result = String(timebuffer);
00355 break;
00356 case ToLocaleString:
00357 strftime(timebuffer, bufsize, cFormat, t);
00358 result = String(timebuffer);
00359 break;
00360 case ToLocaleDateString:
00361 strftime(timebuffer, bufsize, xFormat, t);
00362 result = String(timebuffer);
00363 break;
00364 case ToLocaleTimeString:
00365 strftime(timebuffer, bufsize, "%X", t);
00366 result = String(timebuffer);
00367 break;
00368 case ValueOf:
00369 result = Number(milli);
00370 break;
00371 case GetTime:
00372 result = Number(milli);
00373 break;
00374 case GetYear:
00375
00376 if ( exec->interpreter()->compatMode() != Interpreter::IECompat )
00377 result = Number(t->tm_year);
00378 else
00379 result = Number(1900 + t->tm_year);
00380 break;
00381 case GetFullYear:
00382 result = Number(1900 + t->tm_year);
00383 break;
00384 case GetMonth:
00385 result = Number(t->tm_mon);
00386 break;
00387 case GetDate:
00388 result = Number(t->tm_mday);
00389 break;
00390 case GetDay:
00391 result = Number(t->tm_wday);
00392 break;
00393 case GetHours:
00394 result = Number(t->tm_hour);
00395 break;
00396 case GetMinutes:
00397 result = Number(t->tm_min);
00398 break;
00399 case GetSeconds:
00400 result = Number(t->tm_sec);
00401 break;
00402 case GetMilliSeconds:
00403 result = Number(ms);
00404 break;
00405 case GetTimezoneOffset:
00406 result = Number(timeZoneOffset(t));
00407 break;
00408 case SetTime:
00409 milli = roundValue(exec,args[0]);
00410 result = Number(milli);
00411 thisObj.setInternalValue(result);
00412 break;
00413 case SetMilliSeconds:
00414 ms = args[0].toInt32(exec);
00415 break;
00416 case SetSeconds:
00417 t->tm_sec = args[0].toInt32(exec);
00418 if (args.size() >= 2)
00419 ms = args[1].toInt32(exec);
00420 break;
00421 case SetMinutes:
00422 t->tm_min = args[0].toInt32(exec);
00423 if (args.size() >= 2)
00424 t->tm_sec = args[1].toInt32(exec);
00425 if (args.size() >= 3)
00426 ms = args[2].toInt32(exec);
00427 break;
00428 case SetHours:
00429 t->tm_hour = args[0].toInt32(exec);
00430 if (args.size() >= 2)
00431 t->tm_min = args[1].toInt32(exec);
00432 if (args.size() >= 3)
00433 t->tm_sec = args[2].toInt32(exec);
00434 if (args.size() >= 4)
00435 ms = args[3].toInt32(exec);
00436 break;
00437 case SetDate:
00438 t->tm_mday = args[0].toInt32(exec);
00439 break;
00440 case SetMonth:
00441 t->tm_mon = args[0].toInt32(exec);
00442 if (args.size() >= 2)
00443 t->tm_mday = args[1].toInt32(exec);
00444 break;
00445 case SetFullYear:
00446 t->tm_year = args[0].toInt32(exec) - 1900;
00447 if (args.size() >= 2)
00448 t->tm_mon = args[1].toInt32(exec);
00449 if (args.size() >= 3)
00450 t->tm_mday = args[2].toInt32(exec);
00451 break;
00452 case SetYear: {
00453 int a0 = args[0].toInt32(exec);
00454 if (a0 >= 0 && a0 <= 99)
00455 a0 += 1900;
00456 t->tm_year = a0 - 1900;
00457 break;
00458 }
00459 }
00460
00461 if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
00462 id == SetMinutes || id == SetHours || id == SetDate ||
00463 id == SetMonth || id == SetFullYear ) {
00464 result = Number(makeTime(t, ms, utc));
00465 thisObj.setInternalValue(result);
00466 }
00467
00468 return result;
00469 }
00470
00471
00472
00473
00474
00475 DateObjectImp::DateObjectImp(ExecState *exec,
00476 FunctionPrototypeImp *funcProto,
00477 DatePrototypeImp *dateProto)
00478 : InternalFunctionImp(funcProto)
00479 {
00480 Value protect(this);
00481
00482
00483 putDirect(prototypePropertyName, dateProto, DontEnum|DontDelete|ReadOnly);
00484
00485 static const Identifier parsePropertyName("parse");
00486 putDirect(parsePropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1), DontEnum);
00487 static const Identifier UTCPropertyName("UTC");
00488 putDirect(UTCPropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7), DontEnum);
00489
00490
00491 putDirect(lengthPropertyName, 7, ReadOnly|DontDelete|DontEnum);
00492 }
00493
00494 bool DateObjectImp::implementsConstruct() const
00495 {
00496 return true;
00497 }
00498
00499
00500 Object DateObjectImp::construct(ExecState *exec, const List &args)
00501 {
00502 int numArgs = args.size();
00503
00504 #ifdef KJS_VERBOSE
00505 fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs);
00506 #endif
00507 double value;
00508
00509 if (numArgs == 0) {
00510 #ifdef HAVE_SYS_TIMEB_H
00511 # if defined(__BORLANDC__)
00512 struct timeb timebuffer;
00513 ftime(&timebuffer);
00514 # else
00515 struct _timeb timebuffer;
00516 _ftime(&timebuffer);
00517 # endif
00518 double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);
00519 #else
00520 struct timeval tv;
00521 gettimeofday(&tv, 0L);
00522 double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);
00523 #endif
00524 value = utc;
00525 } else if (numArgs == 1) {
00526 Value prim = args[0].toPrimitive(exec);
00527 if (prim.isA(StringType))
00528 value = parseDate(prim.toString(exec));
00529 else
00530 value = prim.toNumber(exec);
00531 } else {
00532 struct tm t;
00533 memset(&t, 0, sizeof(t));
00534 int year = args[0].toInt32(exec);
00535
00536 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
00537 t.tm_mon = args[1].toInt32(exec);
00538 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
00539 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
00540 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
00541 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
00542 t.tm_isdst = -1;
00543 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
00544 value = makeTime(&t, ms, false);
00545 }
00546
00547 Object proto = exec->interpreter()->builtinDatePrototype();
00548 Object ret(new DateInstanceImp(proto.imp()));
00549 ret.setInternalValue(Number(timeClip(value)));
00550 return ret;
00551 }
00552
00553 bool DateObjectImp::implementsCall() const
00554 {
00555 return true;
00556 }
00557
00558
00559 Value DateObjectImp::call(ExecState* , Object &, const List &)
00560 {
00561 #ifdef KJS_VERBOSE
00562 fprintf(stderr,"DateObjectImp::call - current time\n");
00563 #endif
00564 time_t t = time(0L);
00565 UString s(ctime(&t));
00566
00567
00568 return String(s.substr(0, s.size() - 1));
00569 }
00570
00571
00572
00573 DateObjectFuncImp::DateObjectFuncImp(ExecState* , FunctionPrototypeImp *funcProto,
00574 int i, int len)
00575 : InternalFunctionImp(funcProto), id(i)
00576 {
00577 Value protect(this);
00578 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00579 }
00580
00581 bool DateObjectFuncImp::implementsCall() const
00582 {
00583 return true;
00584 }
00585
00586
00587 Value DateObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00588 {
00589 if (id == Parse) {
00590 return Number(parseDate(args[0].toString(exec)));
00591 } else {
00592 struct tm t;
00593 memset(&t, 0, sizeof(t));
00594 int n = args.size();
00595 int year = args[0].toInt32(exec);
00596
00597 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
00598 t.tm_mon = args[1].toInt32(exec);
00599 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
00600 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
00601 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
00602 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
00603 int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
00604 return Number(makeTime(&t, ms, true));
00605 }
00606 }
00607
00608
00609
00610
00611 double KJS::parseDate(const UString &u)
00612 {
00613 #ifdef KJS_VERBOSE
00614 fprintf(stderr,"KJS::parseDate %s\n",u.ascii());
00615 #endif
00616 double seconds = KRFCDate_parseDate( u );
00617 #ifdef KJS_VERBOSE
00618 fprintf(stderr,"KRFCDate_parseDate returned seconds=%g\n",seconds);
00619 bool withinLimits = true;
00620 if ( sizeof(time_t) == 4 )
00621 {
00622 int limit = ((time_t)-1 < 0) ? 2038 : 2115;
00623 if ( seconds > (limit-1970) * 365.25 * 86400 ) {
00624 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(seconds/(365.25*86400)+1970));
00625 withinLimits = false;
00626 }
00627 }
00628 if ( withinLimits ) {
00629 time_t lsec = (time_t)seconds;
00630 fprintf(stderr, "this is: %s\n", ctime(&lsec));
00631 }
00632 #endif
00633
00634 return seconds == -1 ? NaN : seconds * 1000.0;
00635 }
00636
00638
00639 static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
00640 {
00641
00642
00643 double ret = (day - 32075)
00644 + 1461L * (year + 4800L + (mon - 14) / 12) / 4
00645 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
00646 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
00647 - 2440588;
00648 ret = 24*ret + hour;
00649 ret = 60*ret + minute;
00650 ret = 60*ret + second;
00651
00652 return ret;
00653 }
00654
00655 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
00656
00657
00658
00659 static const struct {
00660 #ifdef _WIN32
00661 char tzName[4];
00662 #else
00663 const char tzName[4];
00664 #endif
00665 int tzOffset;
00666 } known_zones[] = {
00667 { "UT", 0 },
00668 { "GMT", 0 },
00669 { "EST", -300 },
00670 { "EDT", -240 },
00671 { "CST", -360 },
00672 { "CDT", -300 },
00673 { "MST", -420 },
00674 { "MDT", -360 },
00675 { "PST", -480 },
00676 { "PDT", -420 },
00677 { { 0, 0, 0, 0 }, 0 }
00678 };
00679
00680 double KJS::makeTime(struct tm *t, int ms, bool utc)
00681 {
00682 int utcOffset;
00683 if (utc) {
00684 time_t zero = 0;
00685 #if defined BSD || defined(__linux__) || defined(__APPLE__)
00686 struct tm t3;
00687 localtime_r(&zero, &t3);
00688 utcOffset = t3.tm_gmtoff;
00689 t->tm_isdst = t3.tm_isdst;
00690 #else
00691 (void)localtime(&zero);
00692 # if defined(__BORLANDC__)
00693 utcOffset = - _timezone;
00694 # else
00695 utcOffset = - timezone;
00696 # endif
00697 t->tm_isdst = 0;
00698 #endif
00699 } else {
00700 utcOffset = 0;
00701 t->tm_isdst = -1;
00702 }
00703
00704 double yearOffset = 0.0;
00705 if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
00706
00707
00708
00709
00710
00711 int y = t->tm_year + 1900;
00712 int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
00713 const double baseTime = timeFromYear(baseYear);
00714 yearOffset = timeFromYear(y) - baseTime;
00715 t->tm_year = baseYear - 1900;
00716 }
00717
00718 return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset;
00719 }
00720
00721 double KJS::KRFCDate_parseDate(const UString &_date)
00722 {
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737 double result = -1;
00738 int offset = 0;
00739 bool have_tz = false;
00740 char *newPosStr;
00741 const char *dateString = _date.ascii();
00742 int day = 0;
00743 char monthStr[4];
00744 int month = -1;
00745 int year = 0;
00746 int hour = 0;
00747 int minute = 0;
00748 int second = 0;
00749 bool have_time = false;
00750
00751
00752 while(*dateString && isspace(*dateString))
00753 dateString++;
00754
00755 const char *wordStart = dateString;
00756
00757 while(*dateString && !isdigit(*dateString))
00758 {
00759 if ( isspace(*dateString) && dateString - wordStart >= 3 )
00760 {
00761 monthStr[0] = tolower(*wordStart++);
00762 monthStr[1] = tolower(*wordStart++);
00763 monthStr[2] = tolower(*wordStart++);
00764 monthStr[3] = '\0';
00765
00766 const char *str = strstr(haystack, monthStr);
00767 if (str) {
00768 int position = str - haystack;
00769 if (position % 3 == 0) {
00770 month = position / 3;
00771 }
00772 }
00773 while(*dateString && isspace(*dateString))
00774 dateString++;
00775 wordStart = dateString;
00776 }
00777 else
00778 dateString++;
00779 }
00780
00781 while(*dateString && isspace(*dateString))
00782 dateString++;
00783
00784 if (!*dateString)
00785 return invalidDate;
00786
00787
00788 day = strtol(dateString, &newPosStr, 10);
00789 dateString = newPosStr;
00790
00791 if (!*dateString)
00792 return invalidDate;
00793
00794 if (day < 1)
00795 return invalidDate;
00796 if (day > 31) {
00797
00798 if (*dateString == '/' && day >= 1000) {
00799
00800 if (!*++dateString)
00801 return invalidDate;
00802 year = day;
00803 month = strtol(dateString, &newPosStr, 10) - 1;
00804 dateString = newPosStr;
00805 if (*dateString++ != '/' || !*dateString)
00806 return invalidDate;
00807 day = strtol(dateString, &newPosStr, 10);
00808 dateString = newPosStr;
00809 } else {
00810 return invalidDate;
00811 }
00812 } else if (*dateString == '/' && day <= 12 && month == -1)
00813 {
00814 dateString++;
00815
00816 month = day - 1;
00817 day = strtol(dateString, &newPosStr, 10);
00818 dateString = newPosStr;
00819 if (*dateString == '/')
00820 dateString++;
00821 if (!*dateString)
00822 return invalidDate;
00823
00824 }
00825 else
00826 {
00827 if (*dateString == '-')
00828 dateString++;
00829
00830 while(*dateString && isspace(*dateString))
00831 dateString++;
00832
00833 if (*dateString == ',')
00834 dateString++;
00835
00836 if ( month == -1 )
00837 {
00838 for(int i=0; i < 3;i++)
00839 {
00840 if (!*dateString || (*dateString == '-') || isspace(*dateString))
00841 return invalidDate;
00842 monthStr[i] = tolower(*dateString++);
00843 }
00844 monthStr[3] = '\0';
00845
00846 newPosStr = (char*)strstr(haystack, monthStr);
00847
00848 if (!newPosStr || (newPosStr - haystack) % 3 != 0)
00849 return invalidDate;
00850
00851 month = (newPosStr-haystack)/3;
00852
00853 if ((month < 0) || (month > 11))
00854 return invalidDate;
00855
00856 while(*dateString && (*dateString != '-') && !isspace(*dateString))
00857 dateString++;
00858
00859 if (!*dateString)
00860 return invalidDate;
00861
00862
00863 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString))
00864 return invalidDate;
00865 dateString++;
00866 }
00867
00868 if ((month < 0) || (month > 11))
00869 return invalidDate;
00870 }
00871
00872
00873 if (year <= 0 && *dateString)
00874 year = strtol(dateString, &newPosStr, 10);
00875
00876
00877 if (*newPosStr)
00878 {
00879
00880 if (!isspace(*newPosStr)) {
00881 if ( *newPosStr == ':' )
00882 year = -1;
00883 else
00884 return invalidDate;
00885 } else
00886 dateString = ++newPosStr;
00887
00888 have_time = true;
00889 hour = strtol(dateString, &newPosStr, 10);
00890 dateString = newPosStr;
00891
00892 if ((hour < 0) || (hour > 23))
00893 return invalidDate;
00894
00895 if (!*dateString)
00896 return invalidDate;
00897
00898
00899 if (*dateString++ != ':')
00900 return invalidDate;
00901
00902 minute = strtol(dateString, &newPosStr, 10);
00903 dateString = newPosStr;
00904
00905 if ((minute < 0) || (minute > 59))
00906 return invalidDate;
00907
00908
00909 if (*dateString && *dateString != ':' && !isspace(*dateString))
00910 return invalidDate;
00911
00912
00913 if (*dateString ==':') {
00914 dateString++;
00915
00916 second = strtol(dateString, &newPosStr, 10);
00917 dateString = newPosStr;
00918
00919 if ((second < 0) || (second > 59))
00920 return invalidDate;
00921 }
00922
00923 while(*dateString && isspace(*dateString))
00924 dateString++;
00925 }
00926 else
00927 dateString = newPosStr;
00928
00929
00930
00931
00932 if (*dateString) {
00933
00934 if ( (dateString[0] == 'G' && dateString[1] == 'M' && dateString[2] == 'T')
00935 || (dateString[0] == 'U' && dateString[1] == 'T' && dateString[2] == 'C') )
00936 {
00937 dateString += 3;
00938 have_tz = true;
00939 }
00940
00941 while (*dateString && isspace(*dateString))
00942 ++dateString;
00943
00944 if (strncasecmp(dateString, "GMT", 3) == 0) {
00945 dateString += 3;
00946 }
00947 if ((*dateString == '+') || (*dateString == '-')) {
00948 offset = strtol(dateString, &newPosStr, 10);
00949 dateString = newPosStr;
00950
00951 if ((offset < -9959) || (offset > 9959))
00952 return invalidDate;
00953
00954 int sgn = (offset < 0)? -1:1;
00955 offset = abs(offset);
00956 if ( *dateString == ':' ) {
00957 int offset2 = strtol(dateString, &newPosStr, 10);
00958 dateString = newPosStr;
00959 offset = (offset*60 + offset2)*sgn;
00960 }
00961 else
00962 offset = ((offset / 100)*60 + (offset % 100))*sgn;
00963 have_tz = true;
00964 } else {
00965 for (int i=0; known_zones[i].tzName != 0; i++) {
00966 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
00967 offset = known_zones[i].tzOffset;
00968 have_tz = true;
00969 break;
00970 }
00971 }
00972 }
00973 }
00974
00975 while(*dateString && isspace(*dateString))
00976 dateString++;
00977
00978 if ( *dateString && year == -1 ) {
00979 year = strtol(dateString, &newPosStr, 10);
00980 }
00981
00982
00983 if ((year >= 0) && (year < 50))
00984 year += 2000;
00985
00986 if ((year >= 50) && (year < 100))
00987 year += 1900;
00988
00989 if ((year < 1900) || (year > 2500))
00990 return invalidDate;
00991
00992 if (!have_tz) {
00993
00994 struct tm t;
00995 memset(&t, 0, sizeof(tm));
00996 t.tm_mday = day;
00997 t.tm_mon = month;
00998 t.tm_year = year - 1900;
00999 t.tm_isdst = -1;
01000 if (have_time) {
01001 t.tm_sec = second;
01002 t.tm_min = minute;
01003 t.tm_hour = hour;
01004 }
01005
01006 return mktime(&t);
01007 }
01008
01009 offset *= 60;
01010
01011 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
01012
01013
01014 if ((offset > 0) && (offset > result))
01015 offset = 0;
01016
01017 result -= offset;
01018
01019
01020
01021
01022 if (result < 1) result = 1;
01023
01024 return result;
01025 }
01026
01027
01028 double KJS::timeClip(double t)
01029 {
01030 if (isInf(t) || fabs(t) > 8.64E15)
01031 return NaN;
01032 return t;
01033 }
01034