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