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