Changeset 9559 in webkit for trunk/JavaScriptCore/kjs/date_object.cpp
- Timestamp:
- Jul 1, 2005, 11:45:13 AM (20 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/date_object.cpp
r9525 r9559 59 59 #include "date_object.lut.h" 60 60 61 // some constants 61 62 const time_t invalidDate = -1; 63 const double hoursPerDay = 24; 64 const double minutesPerHour = 60; 65 const double secondsPerMinute = 60; 66 const double msPerSecond = 1000; 67 const double msPerMinute = msPerSecond * secondsPerMinute; 68 const double msPerHour = msPerMinute * minutesPerHour; 69 const double msPerDay = msPerHour * hoursPerDay; 62 70 63 71 #if APPLE_CHANGES … … 256 264 } 257 265 258 static UString formatLocaleDate(KJS::ExecState *exec,time_t tv, bool includeDate, bool includeTime, const KJS::List &args) 259 { 260 LongDateTime longDateTime; 261 UCConvertCFAbsoluteTimeToLongDateTime(tv - kCFAbsoluteTimeIntervalSince1970, &longDateTime); 262 266 static UString formatLocaleDate(KJS::ExecState *exec, double time, bool includeDate, bool includeTime, const KJS::List &args) 267 { 263 268 CFLocaleRef locale = CFLocaleCopyCurrent(); 264 265 269 int argCount = args.size(); 266 270 … … 291 295 CFRelease(customFormatCFString); 292 296 } 293 CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(NULL, formatter, tv - kCFAbsoluteTimeIntervalSince1970); 294 297 CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(NULL, formatter, time - kCFAbsoluteTimeIntervalSince1970); 295 298 // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters). 296 299 // That's not great error handling, but it just won't happen so it doesn't matter. … … 313 316 314 317 using namespace KJS; 318 319 static int day(double t) 320 { 321 return int(floor(t / msPerDay)); 322 } 323 324 static double dayFromYear(int year) 325 { 326 return 365.0 * (year - 1970) 327 + floor((year - 1969) / 4.0) 328 - floor((year - 1901) / 100.0) 329 + floor((year - 1601) / 400.0); 330 } 331 332 // depending on whether it's a leap year or not 333 static int daysInYear(int year) 334 { 335 if (year % 4 != 0) 336 return 365; 337 else if (year % 400 == 0) 338 return 366; 339 else if (year % 100 == 0) 340 return 365; 341 else 342 return 366; 343 } 344 345 // time value of the start of a year 346 static double timeFromYear(int year) 347 { 348 return msPerDay * dayFromYear(year); 349 } 350 351 // year determined by time value 352 static int yearFromTime(double t) 353 { 354 // ### there must be an easier way 355 // initial guess 356 int y = 1970 + int(t / (365.25 * msPerDay)); 357 // adjustment 358 if (timeFromYear(y) > t) { 359 do { 360 --y; 361 } while (timeFromYear(y) > t); 362 } else { 363 while (timeFromYear(y + 1) < t) 364 ++y; 365 } 366 367 return y; 368 } 369 370 // 0: Sunday, 1: Monday, etc. 371 static int weekDay(double t) 372 { 373 int wd = (day(t) + 4) % 7; 374 if (wd < 0) 375 wd += 7; 376 return wd; 377 } 378 379 static double timeZoneOffset(const struct tm *t) 380 { 381 #if defined BSD || defined(__linux__) || defined(__APPLE__) 382 return -(t->tm_gmtoff / 60); 383 #else 384 # if defined(__BORLANDC__) || defined(__CYGWIN__) 385 // FIXME consider non one-hour DST change 386 #if !defined(__CYGWIN__) 387 #error please add daylight savings offset here! 388 #endif 389 return _timezone / 60 - (t->tm_isdst > 0 ? 60 : 0); 390 # else 391 return timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 ); 392 # endif 393 #endif 394 } 315 395 316 396 // ------------------------------ DateInstanceImp ------------------------------ … … 462 542 } 463 543 464 time_t tv = (time_t)(milli / 1000.0); 544 // check whether time value is outside time_t's usual range 545 // make the necessary transformations if necessary 546 int realYearOffset = 0; 547 double milliOffset = 0.0; 548 double secs = floor(milli / 1000.0); 549 550 if (milli < 0 || milli >= timeFromYear(2038)) { 551 // ### ugly and probably not very precise 552 int realYear = yearFromTime(milli); 553 int base = daysInYear(realYear) == 365 ? 2001 : 2000; 554 milliOffset = timeFromYear(base) - timeFromYear(realYear); 555 milli += milliOffset; 556 realYearOffset = realYear - base; 557 } 558 559 time_t tv = (time_t) floor(milli / 1000.0); 465 560 int ms = int(milli - tv * 1000.0); 466 561 467 struct tm *t; 468 if (utc) 469 t = gmtime(&tv); 470 else 471 t = localtime(&tv); 472 562 struct tm *t = utc ? gmtime(&tv) : localtime(&tv); 563 // we had an out of range year. use that one (plus/minus offset 564 // found by calculating tm_year) and fix the week day calculation 565 if (realYearOffset != 0) { 566 t->tm_year += realYearOffset; 567 milli -= milliOffset; 568 // our own weekday calculation. beware of need for local time. 569 double m = milli; 570 if (!utc) 571 m -= timeZoneOffset(t) * msPerMinute; 572 t->tm_wday = weekDay(m); 573 } 574 473 575 switch (id) { 474 576 #if APPLE_CHANGES … … 487 589 break; 488 590 case ToLocaleString: 489 result = String(formatLocaleDate(exec, tv, true, true,args));591 result = String(formatLocaleDate(exec, secs, true, true, args)); 490 592 break; 491 593 case ToLocaleDateString: 492 result = String(formatLocaleDate(exec, tv, true, false,args));594 result = String(formatLocaleDate(exec, secs, true, false, args)); 493 595 break; 494 596 case ToLocaleTimeString: 495 result = String(formatLocaleDate(exec, tv, false, true,args));597 result = String(formatLocaleDate(exec, secs, false, true, args)); 496 598 break; 497 599 #else … … 631 733 id == SetMinutes || id == SetHours || id == SetDate || 632 734 id == SetMonth || id == SetFullYear ) { 633 time_t mktimeResult = utc ? timegm(t) : mktime(t); 634 if (mktimeResult == invalidDate) 635 result = Number(NaN); 636 else 637 result = Number(mktimeResult * 1000.0 + ms); 735 result = Number(makeTime(t, ms, utc)); 638 736 thisObj.setInternalValue(result); 639 737 } 640 738 641 739 return result; 642 740 } … … 724 822 t.tm_isdst = -1; 725 823 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0; 726 time_t mktimeResult = mktime(&t); 727 if (mktimeResult == invalidDate) 728 value = NaN; 729 else 730 value = mktimeResult * 1000.0 + ms; 824 value = makeTime(&t, ms, false); 731 825 } 732 826 } 733 827 734 828 Object proto = exec->lexicalInterpreter()->builtinDatePrototype(); 735 829 Object ret(new DateInstanceImp(proto.imp())); … … 818 912 fprintf(stderr,"KJS::parseDate %s\n",u.ascii()); 819 913 #endif 820 int firstSlash = u.find('/'); 821 if ( firstSlash == -1 ) 822 { 823 time_t seconds = KRFCDate_parseDate( u ); 824 #ifdef KJS_VERBOSE 825 fprintf(stderr,"KRFCDate_parseDate returned seconds=%d\n",seconds); 826 #endif 827 if ( seconds == invalidDate ) 828 return NaN; 829 else 830 return seconds * 1000.0; 831 } 832 else 833 { 834 // Found 12/31/2099 on some website -> obviously MM/DD/YYYY 835 int month = u.substr(0,firstSlash).toULong(); 836 int secondSlash = u.find('/',firstSlash+1); 837 //fprintf(stdout,"KJS::parseDate firstSlash=%d, secondSlash=%d\n", firstSlash, secondSlash); 838 if ( secondSlash == -1 ) 839 { 840 fprintf(stderr,"KJS::parseDate parsing for this format isn't implemented\n%s", u.ascii()); 841 return NaN; 842 } 843 int day = u.substr(firstSlash+1,secondSlash-firstSlash-1).toULong(); 844 int year = u.substr(secondSlash+1).toULong(); 845 //fprintf(stdout,"KJS::parseDate day=%d, month=%d, year=%d\n", day, month, year); 846 struct tm t; 847 memset( &t, 0, sizeof(t) ); 848 #if !APPLE_CHANGES 849 year = (year > 2037) ? 2037 : year; // mktime is limited to 2037 !!! 850 #endif 851 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900; 852 t.tm_mon = month-1; // mktime wants 0-11 for some reason 853 t.tm_mday = day; 854 time_t seconds = mktime(&t); 855 if ( seconds == invalidDate ) 856 { 857 #if !APPLE_CHANGES 858 fprintf(stderr,"KJS::parseDate mktime returned -1.\n%s", u.ascii()); 859 #endif 860 return NaN; 861 } 862 else 863 return seconds * 1000.0; 864 } 914 double /*time_t*/ seconds = KRFCDate_parseDate( u ); 915 916 return seconds == invalidDate ? NaN : seconds * 1000.0; 865 917 } 866 918 867 919 ///// Awful duplication from krfcdate.cpp - we don't link to kdecore 868 920 869 static unsigned intymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)870 { 871 unsigned intret = (day - 32075) /* days */921 static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second) 922 { 923 double ret = (day - 32075) /* days */ 872 924 + 1461L * (year + 4800L + (mon - 14) / 12) / 4 873 925 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12 … … 885 937 // we follow the recommendation of rfc2822 to consider all 886 938 // obsolete time zones not listed here equivalent to "-0000" 887 static const struct { 888 const char *tzName; 939 static const struct KnownZone { 940 #ifdef _WIN32 941 char tzName[4]; 942 #else 943 const char tzName[4]; 944 #endif 889 945 int tzOffset; 890 946 } known_zones[] = { … … 898 954 { "MDT", -360 }, 899 955 { "PST", -480 }, 900 { "PDT", -420 }, 901 { 0, 0 } 956 { "PDT", -420 } 902 957 }; 903 958 904 static inline bool isSpaceOrTab(char c) 905 { 906 return c == ' ' || c == '\t'; 907 } 908 909 time_t KJS::KRFCDate_parseDate(const UString &_date) 959 double KJS::makeTime(struct tm *t, int ms, bool utc) 960 { 961 int utcOffset; 962 if (utc) { 963 time_t zero = 0; 964 #if defined BSD || defined(__linux__) || defined(__APPLE__) 965 struct tm *t3 = localtime(&zero); 966 utcOffset = t3->tm_gmtoff; 967 t->tm_isdst = t3->tm_isdst; 968 #else 969 (void)localtime(&zero); 970 # if defined(__BORLANDC__) || defined(__CYGWIN__) 971 utcOffset = - _timezone; 972 # else 973 utcOffset = - timezone; 974 # endif 975 t->tm_isdst = 0; 976 #endif 977 } else { 978 utcOffset = 0; 979 t->tm_isdst = -1; 980 } 981 982 double yearOffset = 0.0; 983 if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) { 984 // we'll fool mktime() into believing that this year is within 985 // its normal, portable range (1970-2038) by setting tm_year to 986 // 2000 or 2001 and adding the difference in milliseconds later. 987 // choice between offset will depend on whether the year is a 988 // leap year or not. 989 int y = t->tm_year + 1900; 990 int baseYear = daysInYear(y) == 365 ? 2001 : 2000; 991 const double baseTime = timeFromYear(baseYear); 992 yearOffset = timeFromYear(y) - baseTime; 993 t->tm_year = baseYear - 1900; 994 } 995 996 return (mktime(t) + utcOffset) * 1000.0 + ms + yearOffset; 997 } 998 999 // returns 0-11 (Jan-Dec); -1 on failure 1000 static int findMonth(const char *monthStr) 1001 { 1002 assert(monthStr); 1003 static const char haystack[37] = "janfebmaraprmayjunjulaugsepoctnovdec"; 1004 char needle[4]; 1005 for (int i = 0; i < 3; ++i) { 1006 if (!*monthStr) 1007 return -1; 1008 needle[i] = tolower(*monthStr++); 1009 } 1010 needle[3] = '\0'; 1011 const char *str = strstr(haystack, needle); 1012 if (str) { 1013 int position = str - haystack; 1014 if (position % 3 == 0) { 1015 return position / 3; 1016 } 1017 } 1018 return -1; 1019 } 1020 1021 double KJS::KRFCDate_parseDate(const UString &_date) 910 1022 { 911 1023 // This parse a date in the form: 912 // Wednesday, 09-Nov-99 23:12:40 GMT1024 // Tuesday, 09-Nov-99 23:12:40 GMT 913 1025 // or 914 1026 // Sat, 01-Jan-2000 08:00:00 GMT … … 917 1029 // or 918 1030 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) 919 // ### non RFC format , added for Javascript:1031 // ### non RFC formats, added for Javascript: 920 1032 // [Wednesday] January 09 1999 23:12:40 GMT 1033 // [Wednesday] January 09 23:12:40 GMT 1999 921 1034 // 922 1035 // We ignore the weekday 923 1036 // 1037 double result = -1; 924 1038 int offset = 0; 1039 bool have_tz = false; 925 1040 char *newPosStr; 926 1041 const char *dateString = _date.ascii(); 927 1042 int day = 0; 928 char monthStr[4];929 1043 int month = -1; // not set yet 930 1044 int year = 0; … … 932 1046 int minute = 0; 933 1047 int second = 0; 934 1048 bool have_time = false; 1049 1050 // for strtol error checking 935 1051 errno = 0; 936 1052 937 1053 // Skip leading space 938 while (isSpaceOrTab(*dateString))1054 while(isspace(*dateString)) 939 1055 dateString++; 940 1056 … … 943 1059 while(*dateString && !isdigit(*dateString)) 944 1060 { 945 if ( is SpaceOrTab(*dateString) && dateString - wordStart >= 3 )1061 if ( isspace(*dateString) && dateString - wordStart >= 3 ) 946 1062 { 947 monthStr[0] = tolower(*wordStart++); 948 monthStr[1] = tolower(*wordStart++); 949 monthStr[2] = tolower(*wordStart++); 950 monthStr[3] = '\0'; 951 //fprintf(stderr,"KJS::parseDate found word starting with '%s'\n", monthStr); 952 const char *str = strstr(haystack, monthStr); 953 if (str) { 954 int position = str - haystack; 955 if (position % 3 == 0) { 956 month = position / 3; // Jan=00, Feb=01, Mar=02, .. 957 } 958 } 959 while (isSpaceOrTab(*dateString)) 1063 month = findMonth(wordStart); 1064 while(isspace(*dateString)) 960 1065 dateString++; 961 1066 wordStart = dateString; … … 964 1069 dateString++; 965 1070 } 966 967 while (isSpaceOrTab(*dateString)) 1071 // missing delimiter between month and day (like "January29")? 1072 if (month == -1 && dateString && wordStart != dateString) { 1073 month = findMonth(wordStart); 1074 // TODO: emit warning about dubious format found 1075 } 1076 1077 while(isspace(*dateString)) 968 1078 dateString++; 969 1079 … … 974 1084 day = strtol(dateString, &newPosStr, 10); 975 1085 if (errno) 976 1086 return invalidDate; 977 1087 dateString = newPosStr; 978 1088 979 if ((day < 1) || (day > 31))980 return invalidDate;981 1089 if (!*dateString) 982 1090 return invalidDate; 983 1091 984 if (*dateString == '-' || *dateString == ',') 1092 if (day < 1) 1093 return invalidDate; 1094 if (day > 31) { 1095 // ### where is the boundary and what happens below? 1096 if (*dateString == '/' && day >= 1000) { 1097 // looks like a YYYY/MM/DD date 1098 if (!*++dateString) 1099 return invalidDate; 1100 year = day; 1101 month = strtol(dateString, &newPosStr, 10) - 1; 1102 if (errno) 1103 return invalidDate; 1104 dateString = newPosStr; 1105 if (*dateString++ != '/' || !*dateString) 1106 return invalidDate; 1107 day = strtol(dateString, &newPosStr, 10); 1108 if (errno) 1109 return invalidDate; 1110 dateString = newPosStr; 1111 } else { 1112 return invalidDate; 1113 } 1114 } else if (*dateString == '/' && day <= 12 && month == -1) { 985 1115 dateString++; 986 987 while (isSpaceOrTab(*dateString)) 988 dateString++; 989 990 if ( month == -1 ) // not found yet 1116 // This looks like a MM/DD/YYYY date, not an RFC date..... 1117 month = day - 1; // 0-based 1118 day = strtol(dateString, &newPosStr, 10); 1119 if (errno) 1120 return invalidDate; 1121 dateString = newPosStr; 1122 if (*dateString == '/') 1123 dateString++; 1124 if (!*dateString) 1125 return invalidDate; 1126 } 1127 else 991 1128 { 992 for(int i=0; i < 3;i++) 993 { 994 if (!*dateString || (*dateString == '-') || isSpaceOrTab(*dateString)) 995 return invalidDate; 996 monthStr[i] = tolower(*dateString++); 997 } 998 monthStr[3] = '\0'; 999 1000 newPosStr = (char*)strstr(haystack, monthStr); 1001 1002 if (!newPosStr || (newPosStr - haystack) % 3 != 0) 1129 if (*dateString == '-') 1130 dateString++; 1131 1132 while(isspace(*dateString)) 1133 dateString++; 1134 1135 if (*dateString == ',') 1136 dateString++; 1137 1138 if ( month == -1 ) // not found yet 1139 { 1140 month = findMonth(dateString); 1141 if (month == -1) 1003 1142 return invalidDate; 1004 1143 1005 month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, .. 1006 1007 if ((month < 0) || (month > 11)) 1144 while(*dateString && (*dateString != '-') && !isspace(*dateString)) 1145 dateString++; 1146 1147 if (!*dateString) 1008 1148 return invalidDate; 1009 1149 1010 while (*dateString && *dateString != '-' && !isSpaceOrTab(*dateString)) 1011 dateString++; 1012 1013 if (!*dateString) 1150 // '-99 23:12:40 GMT' 1151 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString)) 1014 1152 return invalidDate; 1015 1016 // '-99 23:12:40 GMT'1017 if (*dateString != '-' && !isSpaceOrTab(*dateString)) 1018 return invalidDate;1019 dateString++;1153 dateString++; 1154 } 1155 1156 if ((month < 0) || (month > 11)) 1157 return invalidDate; 1020 1158 } 1021 1159 1022 if ((month < 0) || (month > 11))1023 return invalidDate;1024 1025 1160 // '99 23:12:40 GMT' 1026 bool gotYear = true;1027 year = strtol(dateString, &newPosStr, 10);1028 if (errno)1029 return invalidDate;1030 dateString = newPosStr;1031 1161 if (year <= 0 && *dateString) { 1162 year = strtol(dateString, &newPosStr, 10); 1163 if (errno) 1164 return invalidDate; 1165 } 1166 1032 1167 // Don't fail if the time is missing. 1033 if (* dateString == ':' || (isSpaceOrTab(*dateString) && isdigit(dateString[1])))1168 if (*newPosStr) 1034 1169 { 1035 if (*dateString == ':') { 1036 hour = year; 1037 gotYear = false; 1038 } else { 1039 // ' 23:12:40 GMT' 1040 ++dateString; 1041 1042 hour = strtol(dateString, &newPosStr, 10); 1170 // ' 23:12:40 GMT' 1171 if (!isspace(*newPosStr)) { 1172 if ( *newPosStr == ':' ) // Ah, so there was no year, but the number was the hour 1173 year = -1; 1174 else 1175 return invalidDate; 1176 } else // in the normal case (we parsed the year), advance to the next number 1177 dateString = ++newPosStr; 1178 1179 hour = strtol(dateString, &newPosStr, 10); 1180 1181 // Do not check for errno here since we want to continue 1182 // even if errno was set becasue we are still looking 1183 // for the timezone! 1184 // read a number? if not this might be a timezone name 1185 if (newPosStr != dateString) { 1186 have_time = true; 1187 dateString = newPosStr; 1188 1189 if ((hour < 0) || (hour > 23)) 1190 return invalidDate; 1191 1192 if (!*dateString) 1193 return invalidDate; 1194 1195 // ':12:40 GMT' 1196 if (*dateString++ != ':') 1197 return invalidDate; 1198 1199 minute = strtol(dateString, &newPosStr, 10); 1043 1200 if (errno) 1044 1201 return invalidDate; 1045 1202 dateString = newPosStr; 1203 1204 if ((minute < 0) || (minute > 59)) 1205 return invalidDate; 1206 1207 // ':40 GMT' 1208 if (*dateString && *dateString != ':' && !isspace(*dateString)) 1209 return invalidDate; 1210 1211 // seconds are optional in rfc822 + rfc2822 1212 if (*dateString ==':') { 1213 dateString++; 1214 1215 second = strtol(dateString, &newPosStr, 10); 1216 if (errno) 1217 return invalidDate; 1218 dateString = newPosStr; 1219 1220 if ((second < 0) || (second > 59)) 1221 return invalidDate; 1222 } 1223 1224 while(isspace(*dateString)) 1225 dateString++; 1226 1227 if (strncasecmp(dateString, "AM", 2) == 0) { 1228 if (hour > 12) 1229 return invalidDate; 1230 if (hour == 12) 1231 hour = 0; 1232 dateString += 2; 1233 while (isspace(*dateString)) 1234 dateString++; 1235 } else if (strncasecmp(dateString, "PM", 2) == 0) { 1236 if (hour > 12) 1237 return invalidDate; 1238 if (hour != 12) 1239 hour += 12; 1240 dateString += 2; 1241 while (isspace(*dateString)) 1242 dateString++; 1243 } 1046 1244 } 1047 1048 if ((hour < 0) || (hour > 23)) 1245 } else { 1246 dateString = newPosStr; 1247 } 1248 1249 // don't fail if the time zone is missing, some 1250 // broken mail-/news-clients omit the time zone 1251 if (*dateString) { 1252 if (strncasecmp(dateString, "GMT", 3) == 0 || 1253 strncasecmp(dateString, "UTC", 3) == 0) { 1254 dateString += 3; 1255 have_tz = true; 1256 } 1257 1258 while (isspace(*dateString)) 1259 ++dateString; 1260 1261 if (strncasecmp(dateString, "GMT", 3) == 0) { 1262 dateString += 3; 1263 } 1264 if ((*dateString == '+') || (*dateString == '-')) { 1265 offset = strtol(dateString, &newPosStr, 10); 1266 if (errno) 1049 1267 return invalidDate; 1050 1051 if (!*dateString) 1052 return invalidDate; 1053 1054 // ':12:40 GMT' 1055 if (*dateString++ != ':') 1056 return invalidDate; 1057 1058 minute = strtol(dateString, &newPosStr, 10); 1059 if (errno) 1060 return invalidDate; 1061 dateString = newPosStr; 1062 1063 if ((minute < 0) || (minute > 59)) 1064 return invalidDate; 1065 1066 // seconds are optional in rfc822 + rfc2822 1067 if (*dateString ==':') { 1068 dateString++; 1069 1070 second = strtol(dateString, &newPosStr, 10); 1268 dateString = newPosStr; 1269 1270 if ((offset < -9959) || (offset > 9959)) 1271 return invalidDate; 1272 1273 int sgn = (offset < 0)? -1:1; 1274 offset = abs(offset); 1275 if ( *dateString == ':' ) { // GMT+05:00 1276 int offset2 = strtol(dateString, &newPosStr, 10); 1071 1277 if (errno) 1072 1278 return invalidDate; 1073 1279 dateString = newPosStr; 1074 1075 if ((second < 0) || (second > 59)) 1076 return invalidDate; 1077 } 1280 offset = (offset*60 + offset2)*sgn; 1281 } 1282 else 1283 offset = ((offset / 100)*60 + (offset % 100))*sgn; 1284 have_tz = true; 1285 } else { 1286 for (int i=0; i < int(sizeof(known_zones)/sizeof(KnownZone)); i++) { 1287 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { 1288 offset = known_zones[i].tzOffset; 1289 have_tz = true; 1290 break; 1291 } 1292 } 1293 // Bail out if we found an unknown timezone 1294 if (!have_tz) 1295 return invalidDate; 1296 } 1078 1297 } 1079 1080 while (isSpaceOrTab(*dateString))1298 1299 while(isspace(*dateString)) 1081 1300 dateString++; 1082 1301 1083 if (!gotYear) { 1084 year = strtol(dateString, &newPosStr, 10); 1085 if (errno) 1086 return invalidDate; 1087 while (isSpaceOrTab(*dateString)) 1088 dateString++; 1302 if ( *dateString && year == -1 ) { 1303 year = strtol(dateString, &newPosStr, 10); 1304 if (errno) 1305 return invalidDate; 1089 1306 } 1090 1307 … … 1096 1313 year += 1900; // Y2K 1097 1314 1098 if ((year < 1900) || (year > 2500)) 1099 return invalidDate; 1100 1101 if (strncasecmp(dateString, "AM", 2) == 0) { 1102 if (hour < 1 || hour > 12) 1103 return invalidDate; 1104 if (hour == 12) 1105 hour = 0; 1106 dateString += 2; 1107 while (isSpaceOrTab(*dateString)) 1108 dateString++; 1109 } else if (strncasecmp(dateString, "PM", 2) == 0) { 1110 if (hour < 1 || hour > 12) 1111 return invalidDate; 1112 if (hour != 12) 1113 hour += 12; 1114 dateString += 2; 1115 while (isSpaceOrTab(*dateString)) 1116 dateString++; 1315 if (!have_tz) { 1316 // fall back to midnight, local timezone 1317 struct tm t; 1318 memset(&t, 0, sizeof(tm)); 1319 t.tm_mday = day; 1320 t.tm_mon = month; 1321 t.tm_year = year - 1900; 1322 t.tm_isdst = -1; 1323 if (have_time) { 1324 t.tm_sec = second; 1325 t.tm_min = minute; 1326 t.tm_hour = hour; 1327 } 1328 1329 // better not use mktime() as it can't handle the full year range 1330 return makeTime(&t, 0, false) / 1000.0; 1117 1331 } 1118 1119 // don't fail if the time zone is missing, some1120 // broken mail-/news-clients omit the time zone1121 bool localTime;1122 if (*dateString == 0) {1123 // Other web browsers interpret missing time zone as "current time zone".1124 localTime = true;1125 } else {1126 localTime = false;1127 if (strncasecmp(dateString, "GMT", 3) == 0) {1128 dateString += 3;1129 }1130 if ((*dateString == '+') || (*dateString == '-')) {1131 offset = strtol(dateString, &newPosStr, 10);1132 1133 if (errno || (offset < -9959) || (offset > 9959))1134 return invalidDate;1135 1136 int sgn = (offset < 0)? -1:1;1137 offset = abs(offset);1138 offset = ((offset / 100)*60 + (offset % 100))*sgn;1139 } else {1140 for (int i=0; known_zones[i].tzName != 0; i++) {1141 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {1142 offset = known_zones[i].tzOffset;1143 break;1144 }1145 }1146 }1147 }1148 if (sizeof(time_t) == 4)1149 {1150 if ((time_t)-1 < 0)1151 {1152 if (year >= 2038)1153 {1154 year = 2038;1155 month = 0;1156 day = 1;1157 hour = 0;1158 minute = 0;1159 second = 0;1160 }1161 }1162 else1163 {1164 if (year >= 2115)1165 {1166 year = 2115;1167 month = 0;1168 day = 1;1169 hour = 0;1170 minute = 0;1171 second = 0;1172 }1173 }1174 }1175 1176 time_t result;1177 1332 1178 if (localTime) { 1179 struct tm tm; 1180 tm.tm_year = year - 1900; 1181 tm.tm_mon = month; 1182 tm.tm_mday = day; 1183 tm.tm_hour = hour; 1184 tm.tm_min = minute; 1185 tm.tm_sec = second; 1186 tm.tm_isdst = -1; 1187 result = mktime(&tm); 1188 } else { 1189 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second); 1190 1191 // avoid negative time values 1192 if ((offset > 0) && (offset > result)) 1193 offset = 0; 1194 1195 result -= offset*60; 1196 } 1197 1333 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second) - (offset*60); 1198 1334 return result; 1199 1335 }
Note:
See TracChangeset
for help on using the changeset viewer.