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 #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 #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 y0 = (realYear / 100) * 100;
00304 int base = 1900;
00305 if (realYear % 100 == 0)
00306 base += 100;
00307 milliOffset = timeFromYear(base) - timeFromYear(y0);
00308 milli += milliOffset;
00309 realYearOffset = realYear - yearFromTime(milli);
00310 }
00311
00312 time_t tv = (time_t) floor(milli / 1000.0);
00313 int ms = int(milli - tv * 1000.0);
00314
00315 struct tm *t = utc ? gmtime(&tv) : localtime(&tv);
00316
00317
00318
00319 if (realYearOffset != 0) {
00320 t->tm_year += realYearOffset;
00321 milli -= milliOffset;
00322
00323 double m = milli;
00324 if (!utc)
00325 m -= timeZoneOffset(t) * msPerMinute;
00326 t->tm_wday = weekDay(m);
00327 }
00328
00329
00330 const char xFormat[] = "%x";
00331 const char cFormat[] = "%c";
00332
00333 switch (id) {
00334 case ToString:
00335 case ToDateString:
00336 case ToTimeString:
00337 case ToGMTString:
00338 case ToUTCString:
00339 setlocale(LC_TIME,"C");
00340 if (id == DateProtoFuncImp::ToDateString) {
00341 strftime(timebuffer, bufsize, xFormat, t);
00342 } else if (id == DateProtoFuncImp::ToTimeString) {
00343 strftime(timebuffer, bufsize, "%X",t);
00344 } else {
00345 t = (id == ToString ? localtime(&tv) : gmtime(&tv));
00346 strftime(timebuffer, bufsize, "%a, %d %b %Y %H:%M:%S %z", t);
00347 }
00348 setlocale(LC_TIME,oldlocale.c_str());
00349 result = String(timebuffer);
00350 break;
00351 case ToLocaleString:
00352 strftime(timebuffer, bufsize, cFormat, t);
00353 result = String(timebuffer);
00354 break;
00355 case ToLocaleDateString:
00356 strftime(timebuffer, bufsize, xFormat, t);
00357 result = String(timebuffer);
00358 break;
00359 case ToLocaleTimeString:
00360 strftime(timebuffer, bufsize, "%X", t);
00361 result = String(timebuffer);
00362 break;
00363 case ValueOf:
00364 result = Number(milli);
00365 break;
00366 case GetTime:
00367 result = Number(milli);
00368 break;
00369 case GetYear:
00370
00371 if ( exec->interpreter()->compatMode() != Interpreter::IECompat )
00372 result = Number(t->tm_year);
00373 else
00374 result = Number(1900 + t->tm_year);
00375 break;
00376 case GetFullYear:
00377 result = Number(1900 + t->tm_year);
00378 break;
00379 case GetMonth:
00380 result = Number(t->tm_mon);
00381 break;
00382 case GetDate:
00383 result = Number(t->tm_mday);
00384 break;
00385 case GetDay:
00386 result = Number(t->tm_wday);
00387 break;
00388 case GetHours:
00389 result = Number(t->tm_hour);
00390 break;
00391 case GetMinutes:
00392 result = Number(t->tm_min);
00393 break;
00394 case GetSeconds:
00395 result = Number(t->tm_sec);
00396 break;
00397 case GetMilliSeconds:
00398 result = Number(ms);
00399 break;
00400 case GetTimezoneOffset:
00401 result = Number(timeZoneOffset(t));
00402 break;
00403 case SetTime:
00404 milli = roundValue(exec,args[0]);
00405 result = Number(milli);
00406 thisObj.setInternalValue(result);
00407 break;
00408 case SetMilliSeconds:
00409 ms = args[0].toInt32(exec);
00410 break;
00411 case SetSeconds:
00412 t->tm_sec = args[0].toInt32(exec);
00413 if (args.size() >= 2)
00414 ms = args[1].toInt32(exec);
00415 break;
00416 case SetMinutes:
00417 t->tm_min = args[0].toInt32(exec);
00418 if (args.size() >= 2)
00419 t->tm_sec = args[1].toInt32(exec);
00420 if (args.size() >= 3)
00421 ms = args[2].toInt32(exec);
00422 break;
00423 case SetHours:
00424 t->tm_hour = args[0].toInt32(exec);
00425 if (args.size() >= 2)
00426 t->tm_min = args[1].toInt32(exec);
00427 if (args.size() >= 3)
00428 t->tm_sec = args[2].toInt32(exec);
00429 if (args.size() >= 4)
00430 ms = args[3].toInt32(exec);
00431 break;
00432 case SetDate:
00433 t->tm_mday = args[0].toInt32(exec);
00434 break;
00435 case SetMonth:
00436 t->tm_mon = args[0].toInt32(exec);
00437 if (args.size() >= 2)
00438 t->tm_mday = args[1].toInt32(exec);
00439 break;
00440 case SetFullYear:
00441 t->tm_year = args[0].toInt32(exec) - 1900;
00442 if (args.size() >= 2)
00443 t->tm_mon = args[1].toInt32(exec);
00444 if (args.size() >= 3)
00445 t->tm_mday = args[2].toInt32(exec);
00446 break;
00447 case SetYear: {
00448 int a0 = args[0].toInt32(exec);
00449 if (a0 >= 0 && a0 <= 99)
00450 a0 += 1900;
00451 t->tm_year = a0 - 1900;
00452 break;
00453 }
00454 }
00455
00456 if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
00457 id == SetMinutes || id == SetHours || id == SetDate ||
00458 id == SetMonth || id == SetFullYear ) {
00459 result = Number(makeTime(t, ms, utc));
00460 thisObj.setInternalValue(result);
00461 }
00462
00463 return result;
00464 }
00465
00466
00467
00468
00469
00470 DateObjectImp::DateObjectImp(ExecState *exec,
00471 FunctionPrototypeImp *funcProto,
00472 DatePrototypeImp *dateProto)
00473 : InternalFunctionImp(funcProto)
00474 {
00475 Value protect(this);
00476
00477
00478 putDirect(prototypePropertyName, dateProto, DontEnum|DontDelete|ReadOnly);
00479
00480 static const Identifier parsePropertyName("parse");
00481 putDirect(parsePropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1), DontEnum);
00482 static const Identifier UTCPropertyName("UTC");
00483 putDirect(UTCPropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7), DontEnum);
00484
00485
00486 putDirect(lengthPropertyName, 7, ReadOnly|DontDelete|DontEnum);
00487 }
00488
00489 bool DateObjectImp::implementsConstruct() const
00490 {
00491 return true;
00492 }
00493
00494
00495 Object DateObjectImp::construct(ExecState *exec, const List &args)
00496 {
00497 int numArgs = args.size();
00498
00499 #ifdef KJS_VERBOSE
00500 fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs);
00501 #endif
00502 double value;
00503
00504 if (numArgs == 0) {
00505 #if HAVE_SYS_TIMEB_H
00506 # if defined(__BORLANDC__)
00507 struct timeb timebuffer;
00508 ftime(&timebuffer);
00509 # else
00510 struct _timeb timebuffer;
00511 _ftime(&timebuffer);
00512 # endif
00513 double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);
00514 #else
00515 struct timeval tv;
00516 gettimeofday(&tv, 0L);
00517 double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);
00518 #endif
00519 value = utc;
00520 } else if (numArgs == 1) {
00521 Value prim = args[0].toPrimitive(exec);
00522 if (prim.isA(StringType))
00523 value = parseDate(prim.toString(exec));
00524 else
00525 value = prim.toNumber(exec);
00526 } else {
00527 struct tm t;
00528 memset(&t, 0, sizeof(t));
00529 int year = args[0].toInt32(exec);
00530
00531 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
00532 t.tm_mon = args[1].toInt32(exec);
00533 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
00534 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
00535 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
00536 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
00537 t.tm_isdst = -1;
00538 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
00539 value = makeTime(&t, ms, false);
00540 }
00541
00542 Object proto = exec->interpreter()->builtinDatePrototype();
00543 Object ret(new DateInstanceImp(proto.imp()));
00544 ret.setInternalValue(Number(timeClip(value)));
00545 return ret;
00546 }
00547
00548 bool DateObjectImp::implementsCall() const
00549 {
00550 return true;
00551 }
00552
00553
00554 Value DateObjectImp::call(ExecState* , Object &, const List &)
00555 {
00556 #ifdef KJS_VERBOSE
00557 fprintf(stderr,"DateObjectImp::call - current time\n");
00558 #endif
00559 time_t t = time(0L);
00560 UString s(ctime(&t));
00561
00562
00563 return String(s.substr(0, s.size() - 1));
00564 }
00565
00566
00567
00568 DateObjectFuncImp::DateObjectFuncImp(ExecState* , FunctionPrototypeImp *funcProto,
00569 int i, int len)
00570 : InternalFunctionImp(funcProto), id(i)
00571 {
00572 Value protect(this);
00573 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00574 }
00575
00576 bool DateObjectFuncImp::implementsCall() const
00577 {
00578 return true;
00579 }
00580
00581
00582 Value DateObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00583 {
00584 if (id == Parse) {
00585 return Number(parseDate(args[0].toString(exec)));
00586 } else {
00587 struct tm t;
00588 memset(&t, 0, sizeof(t));
00589 int n = args.size();
00590 int year = args[0].toInt32(exec);
00591
00592 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
00593 t.tm_mon = args[1].toInt32(exec);
00594 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
00595 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
00596 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
00597 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
00598 int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
00599 return Number(makeTime(&t, ms, true));
00600 }
00601 }
00602
00603
00604
00605
00606 double KJS::parseDate(const UString &u)
00607 {
00608 #ifdef KJS_VERBOSE
00609 fprintf(stderr,"KJS::parseDate %s\n",u.ascii());
00610 #endif
00611 double seconds = KRFCDate_parseDate( u );
00612 #ifdef KJS_VERBOSE
00613 fprintf(stderr,"KRFCDate_parseDate returned seconds=%g\n",seconds);
00614 bool withinLimits = true;
00615 if ( sizeof(time_t) == 4 )
00616 {
00617 int limit = ((time_t)-1 < 0) ? 2038 : 2115;
00618 if ( seconds > (limit-1970) * 365.25 * 86400 ) {
00619 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(seconds/(365.25*86400)+1970));
00620 withinLimits = false;
00621 }
00622 }
00623 if ( withinLimits ) {
00624 time_t lsec = (time_t)seconds;
00625 fprintf(stderr, "this is: %s\n", ctime(&lsec));
00626 }
00627 #endif
00628
00629 return seconds == -1 ? NaN : seconds * 1000.0;
00630 }
00631
00633
00634 static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
00635 {
00636
00637
00638 double ret = (day - 32075)
00639 + 1461L * (year + 4800L + (mon - 14) / 12) / 4
00640 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
00641 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
00642 - 2440588;
00643 ret = 24*ret + hour;
00644 ret = 60*ret + minute;
00645 ret = 60*ret + second;
00646
00647 return ret;
00648 }
00649
00650 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
00651
00652
00653
00654 static const struct {
00655 const char tzName[4];
00656 int tzOffset;
00657 } known_zones[] = {
00658 { "UT", 0 },
00659 { "GMT", 0 },
00660 { "EST", -300 },
00661 { "EDT", -240 },
00662 { "CST", -360 },
00663 { "CDT", -300 },
00664 { "MST", -420 },
00665 { "MDT", -360 },
00666 { "PST", -480 },
00667 { "PDT", -420 },
00668 { { 0, 0, 0, 0 }, 0 }
00669 };
00670
00671 double KJS::makeTime(struct tm *t, int ms, bool utc)
00672 {
00673 int utcOffset;
00674 if (utc) {
00675 time_t zero = 0;
00676 struct tm t3;
00677 localtime_r(&zero, &t3);
00678 #if defined BSD || defined(__linux__) || defined(__APPLE__)
00679 utcOffset = t3.tm_gmtoff;
00680 t->tm_isdst = t3.tm_isdst;
00681 #else
00682 # if defined(__BORLANDC__)
00683 utcOffset = - _timezone;
00684 # else
00685 utcOffset = - timezone;
00686 # endif
00687 t->tm_isdst = 0;
00688 #endif
00689 } else {
00690 utcOffset = 0;
00691 t->tm_isdst = -1;
00692 }
00693
00694 double yearOffset = 0.0;
00695 if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
00696
00697
00698
00699
00700
00701 int y = t->tm_year + 1900;
00702 int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
00703 const double baseTime = timeFromYear(baseYear);
00704 yearOffset = timeFromYear(y) - baseTime;
00705 t->tm_year = baseYear - 1900;
00706 }
00707
00708 return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset;
00709 }
00710
00711 double KJS::KRFCDate_parseDate(const UString &_date)
00712 {
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 double result = -1;
00728 int offset = 0;
00729 bool have_tz = false;
00730 char *newPosStr;
00731 const char *dateString = _date.ascii();
00732 int day = 0;
00733 char monthStr[4];
00734 int month = -1;
00735 int year = 0;
00736 int hour = 0;
00737 int minute = 0;
00738 int second = 0;
00739 bool have_time = false;
00740
00741
00742 while(*dateString && isspace(*dateString))
00743 dateString++;
00744
00745 const char *wordStart = dateString;
00746
00747 while(*dateString && !isdigit(*dateString))
00748 {
00749 if ( isspace(*dateString) && dateString - wordStart >= 3 )
00750 {
00751 monthStr[0] = tolower(*wordStart++);
00752 monthStr[1] = tolower(*wordStart++);
00753 monthStr[2] = tolower(*wordStart++);
00754 monthStr[3] = '\0';
00755
00756 const char *str = strstr(haystack, monthStr);
00757 if (str) {
00758 int position = str - haystack;
00759 if (position % 3 == 0) {
00760 month = position / 3;
00761 }
00762 }
00763 while(*dateString && isspace(*dateString))
00764 dateString++;
00765 wordStart = dateString;
00766 }
00767 else
00768 dateString++;
00769 }
00770
00771 while(*dateString && isspace(*dateString))
00772 dateString++;
00773
00774 if (!*dateString)
00775 return invalidDate;
00776
00777
00778 day = strtol(dateString, &newPosStr, 10);
00779 dateString = newPosStr;
00780
00781 if (!*dateString)
00782 return invalidDate;
00783
00784 if (day < 1)
00785 return invalidDate;
00786 if (day > 31) {
00787
00788 if (*dateString == '/' && day >= 1000) {
00789
00790 if (!*++dateString)
00791 return invalidDate;
00792 year = day;
00793 month = strtol(dateString, &newPosStr, 10) - 1;
00794 dateString = newPosStr;
00795 if (*dateString++ != '/' || !*dateString)
00796 return invalidDate;
00797 day = strtol(dateString, &newPosStr, 10);
00798 dateString = newPosStr;
00799 } else {
00800 return invalidDate;
00801 }
00802 } else if (*dateString == '/' && day <= 12 && month == -1)
00803 {
00804 dateString++;
00805
00806 month = day - 1;
00807 day = strtol(dateString, &newPosStr, 10);
00808 dateString = newPosStr;
00809 if (*dateString == '/')
00810 dateString++;
00811 if (!*dateString)
00812 return invalidDate;
00813
00814 }
00815 else
00816 {
00817 if (*dateString == '-')
00818 dateString++;
00819
00820 while(*dateString && isspace(*dateString))
00821 dateString++;
00822
00823 if (*dateString == ',')
00824 dateString++;
00825
00826 if ( month == -1 )
00827 {
00828 for(int i=0; i < 3;i++)
00829 {
00830 if (!*dateString || (*dateString == '-') || isspace(*dateString))
00831 return invalidDate;
00832 monthStr[i] = tolower(*dateString++);
00833 }
00834 monthStr[3] = '\0';
00835
00836 newPosStr = (char*)strstr(haystack, monthStr);
00837
00838 if (!newPosStr || (newPosStr - haystack) % 3 != 0)
00839 return invalidDate;
00840
00841 month = (newPosStr-haystack)/3;
00842
00843 if ((month < 0) || (month > 11))
00844 return invalidDate;
00845
00846 while(*dateString && (*dateString != '-') && !isspace(*dateString))
00847 dateString++;
00848
00849 if (!*dateString)
00850 return invalidDate;
00851
00852
00853 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString))
00854 return invalidDate;
00855 dateString++;
00856 }
00857
00858 if ((month < 0) || (month > 11))
00859 return invalidDate;
00860 }
00861
00862
00863 if (year <= 0 && *dateString)
00864 year = strtol(dateString, &newPosStr, 10);
00865
00866
00867 if (*newPosStr)
00868 {
00869
00870 if (!isspace(*newPosStr)) {
00871 if ( *newPosStr == ':' )
00872 year = -1;
00873 else
00874 return invalidDate;
00875 } else
00876 dateString = ++newPosStr;
00877
00878 have_time = true;
00879 hour = strtol(dateString, &newPosStr, 10);
00880 dateString = newPosStr;
00881
00882 if ((hour < 0) || (hour > 23))
00883 return invalidDate;
00884
00885 if (!*dateString)
00886 return invalidDate;
00887
00888
00889 if (*dateString++ != ':')
00890 return invalidDate;
00891
00892 minute = strtol(dateString, &newPosStr, 10);
00893 dateString = newPosStr;
00894
00895 if ((minute < 0) || (minute > 59))
00896 return invalidDate;
00897
00898
00899 if (*dateString && *dateString != ':' && !isspace(*dateString))
00900 return invalidDate;
00901
00902
00903 if (*dateString ==':') {
00904 dateString++;
00905
00906 second = strtol(dateString, &newPosStr, 10);
00907 dateString = newPosStr;
00908
00909 if ((second < 0) || (second > 59))
00910 return invalidDate;
00911 }
00912
00913 while(*dateString && isspace(*dateString))
00914 dateString++;
00915 }
00916 else
00917 dateString = newPosStr;
00918
00919
00920
00921
00922 if (*dateString) {
00923
00924 if ( (dateString[0] == 'G' && dateString[1] == 'M' && dateString[2] == 'T')
00925 || (dateString[0] == 'U' && dateString[1] == 'T' && dateString[2] == 'C') )
00926 {
00927 dateString += 3;
00928 have_tz = true;
00929 }
00930
00931 while (*dateString && isspace(*dateString))
00932 ++dateString;
00933
00934 if (strncasecmp(dateString, "GMT", 3) == 0) {
00935 dateString += 3;
00936 }
00937 if ((*dateString == '+') || (*dateString == '-')) {
00938 offset = strtol(dateString, &newPosStr, 10);
00939 dateString = newPosStr;
00940
00941 if ((offset < -9959) || (offset > 9959))
00942 return invalidDate;
00943
00944 int sgn = (offset < 0)? -1:1;
00945 offset = abs(offset);
00946 if ( *dateString == ':' ) {
00947 int offset2 = strtol(dateString, &newPosStr, 10);
00948 dateString = newPosStr;
00949 offset = (offset*60 + offset2)*sgn;
00950 }
00951 else
00952 offset = ((offset / 100)*60 + (offset % 100))*sgn;
00953 have_tz = true;
00954 } else {
00955 for (int i=0; known_zones[i].tzName != 0; i++) {
00956 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
00957 offset = known_zones[i].tzOffset;
00958 have_tz = true;
00959 break;
00960 }
00961 }
00962 }
00963 }
00964
00965 while(*dateString && isspace(*dateString))
00966 dateString++;
00967
00968 if ( *dateString && year == -1 ) {
00969 year = strtol(dateString, &newPosStr, 10);
00970 }
00971
00972
00973 if ((year >= 0) && (year < 50))
00974 year += 2000;
00975
00976 if ((year >= 50) && (year < 100))
00977 year += 1900;
00978
00979 if ((year < 1900) || (year > 2500))
00980 return invalidDate;
00981
00982 if (!have_tz) {
00983
00984 struct tm t;
00985 memset(&t, 0, sizeof(tm));
00986 t.tm_mday = day;
00987 t.tm_mon = month;
00988 t.tm_year = year - 1900;
00989 t.tm_isdst = -1;
00990 if (have_time) {
00991 t.tm_sec = second;
00992 t.tm_min = minute;
00993 t.tm_hour = hour;
00994 }
00995
00996 return mktime(&t);
00997 }
00998
00999 offset *= 60;
01000
01001 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
01002
01003
01004 if ((offset > 0) && (offset > result))
01005 offset = 0;
01006
01007 result -= offset;
01008
01009
01010
01011
01012 if (result < 1) result = 1;
01013
01014 return result;
01015 }
01016
01017
01018 double KJS::timeClip(double t)
01019 {
01020 if (isInf(t) || fabs(t) > 8.64E15)
01021 return NaN;
01022 return t;
01023 }
01024