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 (!thisObj.inherits(&DateInstanceImp::info)) {
00376
00377
00378
00379
00380 Object err = Error::create(exec,TypeError);
00381 exec->setException(err);
00382 return err;
00383 }
00384
00385
00386 Value result;
00387 UString s;
00388 const int bufsize=100;
00389 char timebuffer[bufsize];
00390 CString oldlocale = setlocale(LC_TIME,NULL);
00391 if (!oldlocale.c_str())
00392 oldlocale = setlocale(LC_ALL, NULL);
00393 Value v = thisObj.internalValue();
00394 double milli = v.toNumber(exec);
00395
00396 if (isNaN(milli)) {
00397 switch (id) {
00398 case ToString:
00399 case ToDateString:
00400 case ToTimeString:
00401 case ToGMTString:
00402 case ToUTCString:
00403 case ToLocaleString:
00404 case ToLocaleDateString:
00405 case ToLocaleTimeString:
00406 return String("Invalid Date");
00407 case ValueOf:
00408 case GetTime:
00409 case GetYear:
00410 case GetFullYear:
00411 case GetMonth:
00412 case GetDate:
00413 case GetDay:
00414 case GetHours:
00415 case GetMinutes:
00416 case GetSeconds:
00417 case GetMilliSeconds:
00418 case GetTimezoneOffset:
00419 case SetMilliSeconds:
00420 case SetSeconds:
00421 case SetMinutes:
00422 case SetHours:
00423 case SetDate:
00424 case SetMonth:
00425 case SetFullYear:
00426 return Number(NaN);
00427 }
00428 }
00429
00430 if (id == SetTime) {
00431 result = Number(roundValue(exec,args[0]));
00432 thisObj.setInternalValue(result);
00433 return result;
00434 }
00435
00436
00437
00438 int realYearOffset = 0;
00439 double milliOffset = 0.0;
00440 if (milli < 0 || milli >= timeFromYear(2038)) {
00441
00442 int realYear = yearFromTime(milli);
00443 int base = daysInYear(realYear) == 365 ? 2001 : 2000;
00444 milliOffset = timeFromYear(base) - timeFromYear(realYear);
00445 milli += milliOffset;
00446 realYearOffset = realYear - base;
00447 }
00448
00449 time_t tv = (time_t) floor(milli / 1000.0);
00450 double ms = milli - tv * 1000.0;
00451
00452 struct tm *t;
00453 if ( (id == DateProtoFuncImp::ToGMTString) ||
00454 (id == DateProtoFuncImp::ToUTCString) )
00455 t = gmtime(&tv);
00456 else if (id == DateProtoFuncImp::ToString)
00457 t = localtime(&tv);
00458 else if (utc)
00459 t = gmtime(&tv);
00460 else
00461 t = localtime(&tv);
00462
00463
00464
00465 if (realYearOffset != 0) {
00466 t->tm_year += realYearOffset;
00467 milli -= milliOffset;
00468
00469 double m = milli;
00470 if (!utc)
00471 m -= timeZoneOffset(t) * msPerMinute;
00472 t->tm_wday = weekDay(m);
00473 }
00474
00475
00476 const char xFormat[] = "%x";
00477 const char cFormat[] = "%c";
00478
00479 switch (id) {
00480 case ToString:
00481 result = String(formatDate(*t) + " " + formatTime(*t));
00482 break;
00483 case ToDateString:
00484 result = String(formatDate(*t));
00485 break;
00486 case ToTimeString:
00487 result = String(formatTime(*t));
00488 break;
00489 case ToGMTString:
00490 case ToUTCString:
00491 result = String(formatDateUTCVariant(*t) + " " + formatTime(*t));
00492 break;
00493 case ToLocaleString:
00494 strftime(timebuffer, bufsize, cFormat, t);
00495 result = String(timebuffer);
00496 break;
00497 case ToLocaleDateString:
00498 strftime(timebuffer, bufsize, xFormat, t);
00499 result = String(timebuffer);
00500 break;
00501 case ToLocaleTimeString:
00502 strftime(timebuffer, bufsize, "%X", t);
00503 result = String(timebuffer);
00504 break;
00505 case ValueOf:
00506 result = Number(milli);
00507 break;
00508 case GetTime:
00509 result = Number(milli);
00510 break;
00511 case GetYear:
00512
00513 if ( exec->dynamicInterpreter()->compatMode() != Interpreter::IECompat )
00514 result = Number(t->tm_year);
00515 else
00516 result = Number(1900 + t->tm_year);
00517 break;
00518 case GetFullYear:
00519 result = Number(1900 + t->tm_year);
00520 break;
00521 case GetMonth:
00522 result = Number(t->tm_mon);
00523 break;
00524 case GetDate:
00525 result = Number(t->tm_mday);
00526 break;
00527 case GetDay:
00528 result = Number(t->tm_wday);
00529 break;
00530 case GetHours:
00531 result = Number(t->tm_hour);
00532 break;
00533 case GetMinutes:
00534 result = Number(t->tm_min);
00535 break;
00536 case GetSeconds:
00537 result = Number(t->tm_sec);
00538 break;
00539 case GetMilliSeconds:
00540 result = Number(ms);
00541 break;
00542 case GetTimezoneOffset:
00543 result = Number(timeZoneOffset(t));
00544 break;
00545 case SetMilliSeconds:
00546 fillStructuresUsingTimeArgs(exec, args, 1, &ms, t);
00547 break;
00548 case SetSeconds:
00549 fillStructuresUsingTimeArgs(exec, args, 2, &ms, t);
00550 break;
00551 case SetMinutes:
00552 fillStructuresUsingTimeArgs(exec, args, 3, &ms, t);
00553 break;
00554 case SetHours:
00555 fillStructuresUsingTimeArgs(exec, args, 4, &ms, t);
00556 break;
00557 case SetDate:
00558 fillStructuresUsingDateArgs(exec, args, 1, &ms, t);
00559 break;
00560 case SetMonth:
00561 fillStructuresUsingDateArgs(exec, args, 2, &ms, t);
00562 break;
00563 case SetFullYear:
00564 fillStructuresUsingDateArgs(exec, args, 3, &ms, t);
00565 break;
00566 case SetYear:
00567 int y = args[0].toInt32(exec);
00568 if (y < 1900) {
00569 if (y >= 0 && y <= 99) {
00570 t->tm_year = y;
00571 } else {
00572 fillStructuresUsingDateArgs(exec, args, 3, &ms, t);
00573 }
00574 } else {
00575 t->tm_year = y - 1900;
00576 }
00577 break;
00578 }
00579
00580 if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
00581 id == SetMinutes || id == SetHours || id == SetDate ||
00582 id == SetMonth || id == SetFullYear ) {
00583 result = Number(makeTime(t, ms, utc));
00584 thisObj.setInternalValue(result);
00585 }
00586
00587 return result;
00588 }
00589
00590
00591
00592
00593
00594 DateObjectImp::DateObjectImp(ExecState *exec,
00595 FunctionPrototypeImp *funcProto,
00596 DatePrototypeImp *dateProto)
00597 : InternalFunctionImp(funcProto)
00598 {
00599 Value protect(this);
00600
00601
00602 putDirect(prototypePropertyName, dateProto, DontEnum|DontDelete|ReadOnly);
00603
00604 static const Identifier parsePropertyName("parse");
00605 putDirect(parsePropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1), DontEnum);
00606 static const Identifier UTCPropertyName("UTC");
00607 putDirect(UTCPropertyName, new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7), DontEnum);
00608
00609
00610 putDirect(lengthPropertyName, 7, ReadOnly|DontDelete|DontEnum);
00611 }
00612
00613 bool DateObjectImp::implementsConstruct() const
00614 {
00615 return true;
00616 }
00617
00618
00619 Object DateObjectImp::construct(ExecState *exec, const List &args)
00620 {
00621 int numArgs = args.size();
00622
00623 #ifdef KJS_VERBOSE
00624 fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs);
00625 #endif
00626 double value;
00627
00628 if (numArgs == 0) {
00629 #ifdef HAVE_SYS_TIMEB_H
00630 # if defined(__BORLANDC__)
00631 struct timeb timebuffer;
00632 ftime(&timebuffer);
00633 # else
00634 struct _timeb timebuffer;
00635 _ftime(&timebuffer);
00636 # endif
00637 double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);
00638 #else
00639 struct timeval tv;
00640 gettimeofday(&tv, 0L);
00641 double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);
00642 #endif
00643 value = utc;
00644 } else if (numArgs == 1) {
00645 Value prim = args[0].toPrimitive(exec);
00646 if (prim.isA(StringType))
00647 value = parseDate(prim.toString(exec));
00648 else
00649 value = prim.toNumber(exec);
00650 } else {
00651 if (isNaN(args[0].toNumber(exec))
00652 || isNaN(args[1].toNumber(exec))
00653 || (numArgs >= 3 && isNaN(args[2].toNumber(exec)))
00654 || (numArgs >= 4 && isNaN(args[3].toNumber(exec)))
00655 || (numArgs >= 5 && isNaN(args[4].toNumber(exec)))
00656 || (numArgs >= 6 && isNaN(args[5].toNumber(exec)))
00657 || (numArgs >= 7 && isNaN(args[6].toNumber(exec)))) {
00658 value = NaN;
00659 } else {
00660 struct tm t;
00661 memset(&t, 0, sizeof(t));
00662 int year = args[0].toInt32(exec);
00663 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
00664 t.tm_mon = args[1].toInt32(exec);
00665 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
00666 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
00667 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
00668 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
00669 t.tm_isdst = -1;
00670 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
00671 value = makeTime(&t, ms, false);
00672 }
00673 }
00674
00675 Object proto = exec->lexicalInterpreter()->builtinDatePrototype();
00676 Object ret(new DateInstanceImp(proto.imp()));
00677 ret.setInternalValue(Number(timeClip(value)));
00678 return ret;
00679 }
00680
00681 bool DateObjectImp::implementsCall() const
00682 {
00683 return true;
00684 }
00685
00686
00687 Value DateObjectImp::call(ExecState* , Object &, const List &)
00688 {
00689 #ifdef KJS_VERBOSE
00690 fprintf(stderr,"DateObjectImp::call - current time\n");
00691 #endif
00692 time_t t = time(0L);
00693
00694 struct tm *tm = localtime(&t);
00695 return String(formatDate(*tm) + " " + formatTime(*tm));
00696 }
00697
00698
00699
00700 DateObjectFuncImp::DateObjectFuncImp(ExecState* , FunctionPrototypeImp *funcProto,
00701 int i, int len)
00702 : InternalFunctionImp(funcProto), id(i)
00703 {
00704 Value protect(this);
00705 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00706 }
00707
00708 bool DateObjectFuncImp::implementsCall() const
00709 {
00710 return true;
00711 }
00712
00713
00714 Value DateObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00715 {
00716 if (id == Parse) {
00717 return Number(parseDate(args[0].toString(exec)));
00718 } else {
00719 int n = args.size();
00720 if (isNaN(args[0].toNumber(exec))
00721 || isNaN(args[1].toNumber(exec))
00722 || (n >= 3 && isNaN(args[2].toNumber(exec)))
00723 || (n >= 4 && isNaN(args[3].toNumber(exec)))
00724 || (n >= 5 && isNaN(args[4].toNumber(exec)))
00725 || (n >= 6 && isNaN(args[5].toNumber(exec)))
00726 || (n >= 7 && isNaN(args[6].toNumber(exec)))) {
00727 return Number(NaN);
00728 }
00729
00730 struct tm t;
00731 memset(&t, 0, sizeof(t));
00732 int year = args[0].toInt32(exec);
00733 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
00734 t.tm_mon = args[1].toInt32(exec);
00735 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
00736 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
00737 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
00738 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
00739 int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
00740 return Number(makeTime(&t, ms, true));
00741 }
00742 }
00743
00744
00745
00746
00747 double KJS::parseDate(const UString &u)
00748 {
00749 #ifdef KJS_VERBOSE
00750 fprintf(stderr,"KJS::parseDate %s\n",u.ascii());
00751 #endif
00752 double seconds = KRFCDate_parseDate( u );
00753
00754 return seconds == invalidDate ? NaN : seconds * 1000.0;
00755 }
00756
00758
00759 static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
00760 {
00761
00762
00763 double ret = (day - 32075)
00764 + 1461L * (year + 4800L + (mon - 14) / 12) / 4
00765 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
00766 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
00767 - 2440588;
00768 ret = 24*ret + hour;
00769 ret = 60*ret + minute;
00770 ret = 60*ret + second;
00771
00772 return ret;
00773 }
00774
00775
00776
00777 static const struct KnownZone {
00778 #ifdef _WIN32
00779 char tzName[4];
00780 #else
00781 const char tzName[4];
00782 #endif
00783 int tzOffset;
00784 } known_zones[] = {
00785 { "UT", 0 },
00786 { "GMT", 0 },
00787 { "EST", -300 },
00788 { "EDT", -240 },
00789 { "CST", -360 },
00790 { "CDT", -300 },
00791 { "MST", -420 },
00792 { "MDT", -360 },
00793 { "PST", -480 },
00794 { "PDT", -420 }
00795 };
00796
00797 double KJS::makeTime(struct tm *t, double ms, bool utc)
00798 {
00799 int utcOffset;
00800 if (utc) {
00801 time_t zero = 0;
00802 #if defined BSD || defined(__linux__) || defined(__APPLE__)
00803 struct tm t3;
00804 localtime_r(&zero, &t3);
00805 utcOffset = t3.tm_gmtoff;
00806 t->tm_isdst = t3.tm_isdst;
00807 #else
00808 (void)localtime(&zero);
00809 # if defined(__BORLANDC__) || defined(__CYGWIN__)
00810 utcOffset = - _timezone;
00811 # else
00812 utcOffset = - timezone;
00813 # endif
00814 t->tm_isdst = 0;
00815 #endif
00816 } else {
00817 utcOffset = 0;
00818 t->tm_isdst = -1;
00819 }
00820
00821 double yearOffset = 0.0;
00822 if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
00823
00824
00825
00826
00827
00828 int y = t->tm_year + 1900;
00829 int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
00830 const double baseTime = timeFromYear(baseYear);
00831 yearOffset = timeFromYear(y) - baseTime;
00832 t->tm_year = baseYear - 1900;
00833 }
00834
00835
00836 if (!utc) {
00837 time_t tval = mktime(t) + utcOffset + int((ms + yearOffset)/1000);
00838 struct tm t3;
00839 localtime_r(&tval, &t3);
00840 t->tm_isdst = t3.tm_isdst;
00841 }
00842
00843 return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset;
00844 }
00845
00846
00847 static int findMonth(const char *monthStr)
00848 {
00849 assert(monthStr);
00850 static const char haystack[37] = "janfebmaraprmayjunjulaugsepoctnovdec";
00851 char needle[4];
00852 for (int i = 0; i < 3; ++i) {
00853 if (!*monthStr)
00854 return -1;
00855 needle[i] = tolower(*monthStr++);
00856 }
00857 needle[3] = '\0';
00858 const char *str = strstr(haystack, needle);
00859 if (str) {
00860 int position = str - haystack;
00861 if (position % 3 == 0) {
00862 return position / 3;
00863 }
00864 }
00865 return -1;
00866 }
00867
00868
00869
00870 static bool isSpaceLike(char c)
00871 {
00872 return isspace(c) || c == ',' || c == ':' || c == '-';
00873 }
00874
00875 double KJS::KRFCDate_parseDate(const UString &_date)
00876 {
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891 double result = -1;
00892 int offset = 0;
00893 bool have_tz = false;
00894 char *newPosStr;
00895 const char *dateString = _date.ascii();
00896 int day = 0;
00897 int month = -1;
00898 int year = 0;
00899 int hour = 0;
00900 int minute = 0;
00901 int second = 0;
00902 bool have_time = false;
00903
00904
00905 while(*dateString && isSpaceLike(*dateString))
00906 dateString++;
00907
00908 const char *wordStart = dateString;
00909
00910 while(*dateString && !isdigit(*dateString))
00911 {
00912 if (isSpaceLike(*dateString) && dateString - wordStart >= 3)
00913 {
00914 month = findMonth(wordStart);
00915 while(*dateString && isSpaceLike(*dateString))
00916 dateString++;
00917 wordStart = dateString;
00918 }
00919 else
00920 dateString++;
00921 }
00922
00923 if (month == -1 && dateString && wordStart != dateString) {
00924 month = findMonth(wordStart);
00925
00926 }
00927
00928 while(*dateString && isSpaceLike(*dateString))
00929 dateString++;
00930
00931 if (!*dateString)
00932 return invalidDate;
00933
00934
00935 errno = 0;
00936 day = strtol(dateString, &newPosStr, 10);
00937 if (errno)
00938 return invalidDate;
00939 dateString = newPosStr;
00940
00941 if (!*dateString)
00942 return invalidDate;
00943
00944 if (day < 0)
00945 return invalidDate;
00946 if (day > 31) {
00947
00948 if (*dateString == '/') {
00949
00950 if (!*++dateString)
00951 return invalidDate;
00952 year = day;
00953 month = strtol(dateString, &newPosStr, 10) - 1;
00954 if (errno)
00955 return invalidDate;
00956 dateString = newPosStr;
00957 if (*dateString++ != '/' || !*dateString)
00958 return invalidDate;
00959 day = strtol(dateString, &newPosStr, 10);
00960 if (errno)
00961 return invalidDate;
00962 dateString = newPosStr;
00963 } else {
00964 return invalidDate;
00965 }
00966 } else if (*dateString == '/' && month == -1)
00967 {
00968 dateString++;
00969
00970 month = day - 1;
00971 day = strtol(dateString, &newPosStr, 10);
00972 if (errno)
00973 return invalidDate;
00974 dateString = newPosStr;
00975 if (*dateString == '/')
00976 dateString++;
00977 if (!*dateString)
00978 return invalidDate;
00979
00980 }
00981 else
00982 {
00983 if (*dateString == '-')
00984 dateString++;
00985
00986 while(*dateString && isSpaceLike(*dateString))
00987 dateString++;
00988
00989 if (*dateString == ',')
00990 dateString++;
00991
00992 if ( month == -1 )
00993 {
00994 month = findMonth(dateString);
00995 if (month == -1)
00996 return invalidDate;
00997
00998 while(*dateString && (*dateString != '-') && !isSpaceLike(*dateString))
00999 dateString++;
01000
01001 if (!*dateString)
01002 return invalidDate;
01003
01004
01005 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString))
01006 return invalidDate;
01007 dateString++;
01008 }
01009
01010 if ((month < 0) || (month > 11))
01011 return invalidDate;
01012 }
01013
01014
01015 if (year <= 0 && *dateString) {
01016 year = strtol(dateString, &newPosStr, 10);
01017 if (errno)
01018 return invalidDate;
01019 }
01020
01021
01022 if (*newPosStr)
01023 {
01024
01025 if (*newPosStr == ':')
01026 year = -1;
01027 else if (isSpaceLike(*newPosStr))
01028 dateString = ++newPosStr;
01029 else
01030 return invalidDate;
01031
01032 hour = strtol(dateString, &newPosStr, 10);
01033
01034
01035
01036
01037
01038 if (newPosStr != dateString) {
01039 have_time = true;
01040 dateString = newPosStr;
01041
01042 if ((hour < 0) || (hour > 23))
01043 return invalidDate;
01044
01045 if (!*dateString)
01046 return invalidDate;
01047
01048
01049 if (*dateString++ != ':')
01050 return invalidDate;
01051
01052 minute = strtol(dateString, &newPosStr, 10);
01053 if (errno)
01054 return invalidDate;
01055 dateString = newPosStr;
01056
01057 if ((minute < 0) || (minute > 59))
01058 return invalidDate;
01059
01060
01061 if (*dateString && *dateString != ':' && !isspace(*dateString))
01062 return invalidDate;
01063
01064
01065 if (*dateString ==':') {
01066 dateString++;
01067
01068 second = strtol(dateString, &newPosStr, 10);
01069 if (errno)
01070 return invalidDate;
01071 dateString = newPosStr;
01072
01073 if ((second < 0) || (second > 59))
01074 return invalidDate;
01075
01076
01077 if (*dateString == ':')
01078 return invalidDate;
01079 }
01080
01081 while(*dateString && isspace(*dateString))
01082 dateString++;
01083
01084 if (strncasecmp(dateString, "AM", 2) == 0) {
01085 if (hour > 12)
01086 return invalidDate;
01087 if (hour == 12)
01088 hour = 0;
01089 dateString += 2;
01090 while (isspace(*dateString))
01091 dateString++;
01092 } else if (strncasecmp(dateString, "PM", 2) == 0) {
01093 if (hour > 12)
01094 return invalidDate;
01095 if (hour != 12)
01096 hour += 12;
01097 dateString += 2;
01098 while (isspace(*dateString))
01099 dateString++;
01100 }
01101 }
01102 } else {
01103 dateString = newPosStr;
01104 }
01105
01106
01107
01108 if (*dateString) {
01109
01110 if (strncasecmp(dateString, "GMT", 3) == 0 ||
01111 strncasecmp(dateString, "UTC", 3) == 0)
01112 {
01113 dateString += 3;
01114 have_tz = true;
01115 }
01116
01117 while (*dateString && isspace(*dateString))
01118 ++dateString;
01119
01120 if (strncasecmp(dateString, "GMT", 3) == 0) {
01121 dateString += 3;
01122 }
01123 if ((*dateString == '+') || (*dateString == '-')) {
01124 offset = strtol(dateString, &newPosStr, 10);
01125 if (errno)
01126 return invalidDate;
01127 dateString = newPosStr;
01128
01129 if ((offset < -9959) || (offset > 9959))
01130 return invalidDate;
01131
01132 int sgn = (offset < 0)? -1:1;
01133 offset = abs(offset);
01134 if ( *dateString == ':' ) {
01135 int offset2 = strtol(dateString, &newPosStr, 10);
01136 if (errno)
01137 return invalidDate;
01138 dateString = newPosStr;
01139 offset = (offset*60 + offset2)*sgn;
01140 }
01141 else
01142 offset = ((offset / 100)*60 + (offset % 100))*sgn;
01143 have_tz = true;
01144 } else {
01145 for (int i=0; i < int(sizeof(known_zones)/sizeof(KnownZone)); i++) {
01146 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
01147 offset = known_zones[i].tzOffset;
01148 dateString += strlen(known_zones[i].tzName);
01149 have_tz = true;
01150 break;
01151 }
01152 }
01153 }
01154 }
01155
01156 while(*dateString && isspace(*dateString))
01157 dateString++;
01158
01159 if ( *dateString && year == -1 ) {
01160 year = strtol(dateString, &newPosStr, 10);
01161 if (errno)
01162 return invalidDate;
01163 dateString = newPosStr;
01164 }
01165
01166 while (isspace(*dateString))
01167 dateString++;
01168
01169 #if 0
01170
01171 if (*dateString != '\0')
01172 return invalidDate;
01173 #endif
01174
01175
01176 if ((year >= 0) && (year < 50))
01177 year += 2000;
01178
01179 if ((year >= 50) && (year < 100))
01180 year += 1900;
01181
01182 if (!have_tz) {
01183
01184 struct tm t;
01185 memset(&t, 0, sizeof(tm));
01186 t.tm_mday = day;
01187 t.tm_mon = month;
01188 t.tm_year = year - 1900;
01189 t.tm_isdst = -1;
01190 if (have_time) {
01191 t.tm_sec = second;
01192 t.tm_min = minute;
01193 t.tm_hour = hour;
01194 }
01195
01196
01197 return makeTime(&t, 0, false) / 1000.0;
01198 }
01199
01200 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second) - offset*60;
01201 return result;
01202 }
01203
01204
01205 double KJS::timeClip(double t)
01206 {
01207 if (isInf(t))
01208 return NaN;
01209 double at = fabs(t);
01210 if (at > 8.64E15)
01211 return NaN;
01212 return floor(at) * (t != at ? -1 : 1);
01213 }
01214