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 SetTime:
00421 case SetMilliSeconds:
00422 case SetSeconds:
00423 case SetMinutes:
00424 case SetHours:
00425 case SetDate:
00426 case SetMonth:
00427 case SetFullYear:
00428 return Number(NaN);
00429 }
00430 }
00431
00432
00433
00434 int realYearOffset = 0;
00435 double milliOffset = 0.0;
00436 if (milli < 0 || milli >= timeFromYear(2038)) {
00437
00438 int realYear = yearFromTime(milli);
00439 int base = daysInYear(realYear) == 365 ? 2001 : 2000;
00440 milliOffset = timeFromYear(base) - timeFromYear(realYear);
00441 milli += milliOffset;
00442 realYearOffset = realYear - base;
00443 }
00444
00445 time_t tv = (time_t) floor(milli / 1000.0);
00446 double ms = milli - tv * 1000.0;
00447
00448 struct tm *t;
00449 if ( (id == DateProtoFuncImp::ToGMTString) ||
00450 (id == DateProtoFuncImp::ToUTCString) )
00451 t = gmtime(&tv);
00452 else if (id == DateProtoFuncImp::ToString)
00453 t = localtime(&tv);
00454 else if (utc)
00455 t = gmtime(&tv);
00456 else
00457 t = localtime(&tv);
00458
00459
00460
00461 if (realYearOffset != 0) {
00462 t->tm_year += realYearOffset;
00463 milli -= milliOffset;
00464
00465 double m = milli;
00466 if (!utc)
00467 m -= timeZoneOffset(t) * msPerMinute;
00468 t->tm_wday = weekDay(m);
00469 }
00470
00471
00472 const char xFormat[] = "%x";
00473 const char cFormat[] = "%c";
00474
00475 switch (id) {
00476 case ToString:
00477 result = String(formatDate(*t) + " " + formatTime(*t));
00478 break;
00479 case ToDateString:
00480 result = String(formatDate(*t));
00481 break;
00482 case ToTimeString:
00483 result = String(formatTime(*t));
00484 break;
00485 case ToGMTString:
00486 case ToUTCString:
00487 result = String(formatDateUTCVariant(*t) + " " + formatTime(*t));
00488 break;
00489 case ToLocaleString:
00490 strftime(timebuffer, bufsize, cFormat, t);
00491 result = String(timebuffer);
00492 break;
00493 case ToLocaleDateString:
00494 strftime(timebuffer, bufsize, xFormat, t);
00495 result = String(timebuffer);
00496 break;
00497 case ToLocaleTimeString:
00498 strftime(timebuffer, bufsize, "%X", t);
00499 result = String(timebuffer);
00500 break;
00501 case ValueOf:
00502 result = Number(milli);
00503 break;
00504 case GetTime:
00505 result = Number(milli);
00506 break;
00507 case GetYear:
00508
00509 if ( exec->dynamicInterpreter()->compatMode() != Interpreter::IECompat )
00510 result = Number(t->tm_year);
00511 else
00512 result = Number(1900 + t->tm_year);
00513 break;
00514 case GetFullYear:
00515 result = Number(1900 + t->tm_year);
00516 break;
00517 case GetMonth:
00518 result = Number(t->tm_mon);
00519 break;
00520 case GetDate:
00521 result = Number(t->tm_mday);
00522 break;
00523 case GetDay:
00524 result = Number(t->tm_wday);
00525 break;
00526 case GetHours:
00527 result = Number(t->tm_hour);
00528 break;
00529 case GetMinutes:
00530 result = Number(t->tm_min);
00531 break;
00532 case GetSeconds:
00533 result = Number(t->tm_sec);
00534 break;
00535 case GetMilliSeconds:
00536 result = Number(ms);
00537 break;
00538 case GetTimezoneOffset:
00539 result = Number(timeZoneOffset(t));
00540 break;
00541 case SetTime:
00542 milli = roundValue(exec,args[0]);
00543 result = Number(milli);
00544 thisObj.setInternalValue(result);
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 double KJS::KRFCDate_parseDate(const UString &_date)
00870 {
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885 double result = -1;
00886 int offset = 0;
00887 bool have_tz = false;
00888 char *newPosStr;
00889 const char *dateString = _date.ascii();
00890 int day = 0;
00891 int month = -1;
00892 int year = 0;
00893 int hour = 0;
00894 int minute = 0;
00895 int second = 0;
00896 bool have_time = false;
00897
00898
00899 while(*dateString && isspace(*dateString))
00900 dateString++;
00901
00902 const char *wordStart = dateString;
00903
00904 while(*dateString && !isdigit(*dateString))
00905 {
00906 if ( isspace(*dateString) && dateString - wordStart >= 3 )
00907 {
00908 month = findMonth(wordStart);
00909 while(*dateString && isspace(*dateString))
00910 dateString++;
00911 wordStart = dateString;
00912 }
00913 else
00914 dateString++;
00915 }
00916
00917 if (month == -1 && dateString && wordStart != dateString) {
00918 month = findMonth(wordStart);
00919
00920 }
00921
00922 while(*dateString && isspace(*dateString))
00923 dateString++;
00924
00925 if (!*dateString)
00926 return invalidDate;
00927
00928
00929 errno = 0;
00930 day = strtol(dateString, &newPosStr, 10);
00931 if (errno)
00932 return invalidDate;
00933 dateString = newPosStr;
00934
00935 if (!*dateString)
00936 return invalidDate;
00937
00938 if (day < 0)
00939 return invalidDate;
00940 if (day > 31) {
00941
00942 if (*dateString == '/') {
00943
00944 if (!*++dateString)
00945 return invalidDate;
00946 year = day;
00947 month = strtol(dateString, &newPosStr, 10) - 1;
00948 if (errno)
00949 return invalidDate;
00950 dateString = newPosStr;
00951 if (*dateString++ != '/' || !*dateString)
00952 return invalidDate;
00953 day = strtol(dateString, &newPosStr, 10);
00954 if (errno)
00955 return invalidDate;
00956 dateString = newPosStr;
00957 } else {
00958 return invalidDate;
00959 }
00960 } else if (*dateString == '/' && month == -1)
00961 {
00962 dateString++;
00963
00964 month = day - 1;
00965 day = strtol(dateString, &newPosStr, 10);
00966 if (errno)
00967 return invalidDate;
00968 dateString = newPosStr;
00969 if (*dateString == '/')
00970 dateString++;
00971 if (!*dateString)
00972 return invalidDate;
00973
00974 }
00975 else
00976 {
00977 if (*dateString == '-')
00978 dateString++;
00979
00980 while(*dateString && isspace(*dateString))
00981 dateString++;
00982
00983 if (*dateString == ',')
00984 dateString++;
00985
00986 if ( month == -1 )
00987 {
00988 month = findMonth(dateString);
00989 if (month == -1)
00990 return invalidDate;
00991
00992 while(*dateString && (*dateString != '-') && !isspace(*dateString))
00993 dateString++;
00994
00995 if (!*dateString)
00996 return invalidDate;
00997
00998
00999 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString))
01000 return invalidDate;
01001 dateString++;
01002 }
01003
01004 if ((month < 0) || (month > 11))
01005 return invalidDate;
01006 }
01007
01008
01009 if (year <= 0 && *dateString) {
01010 year = strtol(dateString, &newPosStr, 10);
01011 if (errno)
01012 return invalidDate;
01013 }
01014
01015
01016 if (*newPosStr)
01017 {
01018
01019 if (!isspace(*newPosStr)) {
01020 if ( *newPosStr == ':' )
01021 year = -1;
01022 else
01023 return invalidDate;
01024 } else
01025 dateString = ++newPosStr;
01026
01027 hour = strtol(dateString, &newPosStr, 10);
01028
01029
01030
01031
01032
01033 if (newPosStr != dateString) {
01034 have_time = true;
01035 dateString = newPosStr;
01036
01037 if ((hour < 0) || (hour > 23))
01038 return invalidDate;
01039
01040 if (!*dateString)
01041 return invalidDate;
01042
01043
01044 if (*dateString++ != ':')
01045 return invalidDate;
01046
01047 minute = strtol(dateString, &newPosStr, 10);
01048 if (errno)
01049 return invalidDate;
01050 dateString = newPosStr;
01051
01052 if ((minute < 0) || (minute > 59))
01053 return invalidDate;
01054
01055
01056 if (*dateString && *dateString != ':' && !isspace(*dateString))
01057 return invalidDate;
01058
01059
01060 if (*dateString ==':') {
01061 dateString++;
01062
01063 second = strtol(dateString, &newPosStr, 10);
01064 if (errno)
01065 return invalidDate;
01066 dateString = newPosStr;
01067
01068 if ((second < 0) || (second > 59))
01069 return invalidDate;
01070 }
01071
01072 while(*dateString && isspace(*dateString))
01073 dateString++;
01074
01075 if (strncasecmp(dateString, "AM", 2) == 0) {
01076 if (hour > 12)
01077 return invalidDate;
01078 if (hour == 12)
01079 hour = 0;
01080 dateString += 2;
01081 while (isspace(*dateString))
01082 dateString++;
01083 } else if (strncasecmp(dateString, "PM", 2) == 0) {
01084 if (hour > 12)
01085 return invalidDate;
01086 if (hour != 12)
01087 hour += 12;
01088 dateString += 2;
01089 while (isspace(*dateString))
01090 dateString++;
01091 }
01092 }
01093 } else {
01094 dateString = newPosStr;
01095 }
01096
01097
01098
01099 if (*dateString) {
01100
01101 if (strncasecmp(dateString, "GMT", 3) == 0 ||
01102 strncasecmp(dateString, "UTC", 3) == 0)
01103 {
01104 dateString += 3;
01105 have_tz = true;
01106 }
01107
01108 while (*dateString && isspace(*dateString))
01109 ++dateString;
01110
01111 if (strncasecmp(dateString, "GMT", 3) == 0) {
01112 dateString += 3;
01113 }
01114 if ((*dateString == '+') || (*dateString == '-')) {
01115 offset = strtol(dateString, &newPosStr, 10);
01116 if (errno)
01117 return invalidDate;
01118 dateString = newPosStr;
01119
01120 if ((offset < -9959) || (offset > 9959))
01121 return invalidDate;
01122
01123 int sgn = (offset < 0)? -1:1;
01124 offset = abs(offset);
01125 if ( *dateString == ':' ) {
01126 int offset2 = strtol(dateString, &newPosStr, 10);
01127 if (errno)
01128 return invalidDate;
01129 dateString = newPosStr;
01130 offset = (offset*60 + offset2)*sgn;
01131 }
01132 else
01133 offset = ((offset / 100)*60 + (offset % 100))*sgn;
01134 have_tz = true;
01135 } else {
01136 for (int i=0; i < int(sizeof(known_zones)/sizeof(KnownZone)); i++) {
01137 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
01138 offset = known_zones[i].tzOffset;
01139 dateString += strlen(known_zones[i].tzName);
01140 have_tz = true;
01141 break;
01142 }
01143 }
01144 }
01145 }
01146
01147 while(*dateString && isspace(*dateString))
01148 dateString++;
01149
01150 if ( *dateString && year == -1 ) {
01151 year = strtol(dateString, &newPosStr, 10);
01152 if (errno)
01153 return invalidDate;
01154 dateString = newPosStr;
01155 }
01156
01157 while (isspace(*dateString))
01158 dateString++;
01159
01160 #if 0
01161
01162 if (*dateString != '\0')
01163 return invalidDate;
01164 #endif
01165
01166
01167 if ((year >= 0) && (year < 50))
01168 year += 2000;
01169
01170 if ((year >= 50) && (year < 100))
01171 year += 1900;
01172
01173 if (!have_tz) {
01174
01175 struct tm t;
01176 memset(&t, 0, sizeof(tm));
01177 t.tm_mday = day;
01178 t.tm_mon = month;
01179 t.tm_year = year - 1900;
01180 t.tm_isdst = -1;
01181 if (have_time) {
01182 t.tm_sec = second;
01183 t.tm_min = minute;
01184 t.tm_hour = hour;
01185 }
01186
01187
01188 return makeTime(&t, 0, false) / 1000.0;
01189 }
01190
01191 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second) - offset*60;
01192 return result;
01193 }
01194
01195
01196 double KJS::timeClip(double t)
01197 {
01198 if (isInf(t))
01199 return NaN;
01200 double at = fabs(t);
01201 if (at > 8.64E15)
01202 return NaN;
01203 return floor(at) * (t != at ? -1 : 1);
01204 }
01205