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