00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #define FREPPLE_CORE
00028 #include "frepple/utils.h"
00029 #include <ctime>
00030 #include <clocale>
00031
00032
00033 namespace frepple
00034 {
00035 namespace utils
00036 {
00037
00038 DECLARE_EXPORT string Date::format("%Y-%m-%dT%H:%M:%S");
00039 DECLARE_EXPORT string DateRange::separator = " / ";
00040 DECLARE_EXPORT size_t DateRange::separatorlength = 3;
00041
00042
00043
00044
00045
00046 DECLARE_EXPORT const Date Date::infinitePast("1971-01-01T00:00:00",true);
00047
00048
00049
00050 DECLARE_EXPORT const Date Date::infiniteFuture("2030-12-31T00:00:00",true);
00051
00052 DECLARE_EXPORT const TimePeriod TimePeriod::MAX(Date::infiniteFuture - Date::infinitePast);
00053 DECLARE_EXPORT const TimePeriod TimePeriod::MIN(Date::infinitePast - Date::infiniteFuture);
00054
00055
00056 DECLARE_EXPORT void Date::checkFinite(long long i)
00057 {
00058 if (i > infiniteFuture.lval) lval = infiniteFuture.lval;
00059 else if (i < infinitePast.lval) lval = infinitePast.lval;
00060 else lval = static_cast<long>(i);
00061 }
00062
00063
00064 DECLARE_EXPORT void TimePeriod::toCharBuffer(char* t) const
00065 {
00066 if (!lval)
00067 {
00068 sprintf(t,"P0D");
00069 return;
00070 }
00071 long tmp = (lval>0 ? lval : -lval);
00072 if (lval<0) *(t++) = '-';
00073 *(t++) = 'P';
00074 if (tmp >= 31536000L)
00075 {
00076 long y = tmp / 31536000L;
00077 t += sprintf(t,"%liY", y);
00078 tmp %= 31536000L;
00079 }
00080 if (tmp >= 86400L)
00081 {
00082 long d = tmp / 86400L;
00083 t += sprintf(t,"%liD", d);
00084 tmp %= 86400L;
00085 }
00086 if (tmp > 0L)
00087 {
00088 *(t++) = 'T';
00089 if (tmp >= 3600L)
00090 {
00091 long h = tmp / 3600L;
00092 t += sprintf(t,"%liH", h);
00093 tmp %= 3600L;
00094 }
00095 if (tmp >= 60L)
00096 {
00097 long h = tmp / 60L;
00098 t += sprintf(t,"%liM", h);
00099 tmp %= 60L;
00100 }
00101 if (tmp > 0L)
00102 sprintf(t,"%liS", tmp);
00103 }
00104 }
00105
00106
00107 DECLARE_EXPORT DateRange::operator string() const
00108 {
00109
00110 char r[65];
00111 char *pos = r + start.toCharBuffer(r);
00112
00113
00114 strcat(pos, separator.c_str());
00115 pos += separatorlength;
00116
00117
00118 end.toCharBuffer(pos);
00119 return r;
00120 }
00121
00122
00123 DECLARE_EXPORT size_t Date::toCharBuffer(char* str) const
00124 {
00125
00126
00127
00128
00129
00130
00131
00132 #ifdef HAVE_LOCALTIME_R
00133 struct tm timeStruct;
00134 localtime_r(&lval, &timeStruct);
00135 #else
00136 struct tm timeStruct = *localtime(&lval);
00137 #endif
00138 return strftime(str, 30, format.c_str(), &timeStruct);
00139 }
00140
00141
00142 DECLARE_EXPORT void TimePeriod::parse (const char* s)
00143 {
00144 long totalvalue = 0;
00145 long value = 0;
00146 bool negative = false;
00147 const char *c = s;
00148
00149
00150 if (*c == '-')
00151 {
00152 negative = true;
00153 ++c;
00154 }
00155
00156
00157 if (*c != 'P')
00158 throw DataException("Invalid time string '" + string(s) + "'");
00159 ++c;
00160
00161
00162 for ( ; *c && *c != 'T'; ++c)
00163 {
00164 switch (*c)
00165 {
00166 case '0': case '1': case '2': case '3': case '4':
00167 case '5': case '6': case '7': case '8': case '9':
00168 value = value * 10 + (*c - '0');
00169 break;
00170 case 'Y':
00171 totalvalue += value * 31536000L;
00172 value = 0;
00173 break;
00174 case 'M':
00175
00176 totalvalue += value * 2628000L;
00177 value = 0;
00178 break;
00179 case 'W':
00180 totalvalue += value * 604800L;
00181 value = 0;
00182 break;
00183 case 'D':
00184 totalvalue += value * 86400L;
00185 value = 0;
00186 break;
00187 default:
00188 throw DataException("Invalid time string '" + string(s) + "'");
00189 }
00190 }
00191
00192
00193 if (*c == 'T')
00194 {
00195 for (++c ; *c; ++c)
00196 {
00197 switch (*c)
00198 {
00199 case '0': case '1': case '2': case '3': case '4':
00200 case '5': case '6': case '7': case '8': case '9':
00201 value = value * 10 + (*c - '0');
00202 break;
00203 case 'H':
00204 totalvalue += value * 3600L;
00205 value = 0;
00206 break;
00207 case 'M':
00208 totalvalue += value * 60L;
00209 value = 0;
00210 break;
00211 case 'S':
00212 totalvalue += value;
00213 value = 0;
00214 break;
00215 default:
00216 throw DataException("Invalid time string '" + string(s) + "'");
00217 }
00218 }
00219 }
00220
00221
00222 if (value) throw DataException("Invalid time string '" + string(s) + "'");
00223
00224
00225 lval = negative ? -totalvalue : totalvalue;
00226 }
00227
00228
00229 DECLARE_EXPORT void Date::parse (const char* s, const string& fmt)
00230 {
00231 if (!s)
00232 {
00233
00234 lval = infinitePast.lval;
00235 return;
00236 }
00237 struct tm p;
00238 strptime(s, fmt.c_str(), &p);
00239
00240 p.tm_isdst = -1;
00241 lval = mktime(&p);
00242 }
00243
00244
00245 DECLARE_EXPORT Date::Date
00246 (int year, int month, int day, int hr, int min, int sec)
00247 {
00248 struct tm p;
00249 p.tm_isdst = -1;
00250 p.tm_year = year - 1900;
00251 p.tm_mon = month - 1;
00252 p.tm_mday = day;
00253 p.tm_hour = hr;
00254 p.tm_min = min;
00255 p.tm_sec = sec;
00256 lval = mktime(&p);
00257 checkFinite(lval);
00258 }
00259
00260
00261
00262
00263 #ifndef HAVE_STRPTIME
00264
00265 DECLARE_EXPORT char* Date::strptime(const char *buf, const char *fmt, struct tm *tm)
00266 {
00267 struct dtconv
00268 {
00269 char *abbrev_month_names[12];
00270 size_t len_abbrev_month_names[12];
00271 char *month_names[12];
00272 size_t len_month_names[12];
00273 char *abbrev_weekday_names[7];
00274 size_t len_abbrev_weekday_names[7];
00275 char *weekday_names[7];
00276 size_t len_weekday_names[7];
00277 char *time_format;
00278 char *sDate_format;
00279 char *dtime_format;
00280 char *am_string;
00281 size_t len_am_string;
00282 char *pm_string;
00283 size_t len_pm_string;
00284 char *lDate_format;
00285 unsigned short numWeekdays;
00286 unsigned short numMonths;
00287 };
00288
00289
00290 static struct dtconv En_US =
00291 {
00292 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00293 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00294 },
00295 { 3, 3, 3, 3, 3, 3,
00296 3, 3, 3, 3, 3, 3},
00297 { "January", "February", "March", "April", "May", "June", "July", "August",
00298 "September", "October", "November", "December" },
00299 { 8, 8, 5, 5, 3, 4, 4, 6,
00300 9, 7, 8, 8},
00301 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
00302 { 3, 3, 3, 3, 3, 3, 3},
00303 { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
00304 "Saturday" },
00305 { 6, 6, 7, 9, 8, 6,
00306 8},
00307 "%H:%M:%S",
00308 "%m/%d/%y",
00309 "%a %b %e %T %Z %Y",
00310 "AM",
00311 2,
00312 "PM",
00313 2,
00314 "%A, %B, %e, %Y",
00315 7,
00316 12
00317 };
00318
00319 char c, *ptr;
00320 short i, len = 0;
00321
00322
00323 tm->tm_isdst = -1;
00324
00325 ptr = (char*) fmt;
00326 while (*ptr != 0)
00327 {
00328
00329 if (*buf == 0) break;
00330 c = *ptr++;
00331 if (c != '%')
00332 {
00333 if (isspace(c))
00334 while (*buf != 0 && isspace(*buf)) buf++;
00335 else if (c != *buf++) return 0;
00336 continue;
00337 }
00338
00339 c = *ptr++;
00340 switch (c)
00341 {
00342 case 0:
00343 case '%':
00344 if (*buf++ != '%') return 0;
00345 break;
00346
00347 case 'C':
00348 buf = strptime(buf, En_US.lDate_format, tm);
00349 if (buf == 0) return 0;
00350 break;
00351
00352 case 'c':
00353 buf = strptime(buf, "%x %X", tm);
00354 if (buf == 0) return 0;
00355 break;
00356
00357 case 'D':
00358 buf = strptime(buf, "%m/%d/%y", tm);
00359 if (buf == 0) return 0;
00360 break;
00361
00362 case 'R':
00363 buf = strptime(buf, "%H:%M", tm);
00364 if (buf == 0) return 0;
00365 break;
00366
00367 case 'r':
00368 buf = strptime(buf, "%I:%M:%S %p", tm);
00369 if (buf == 0) return 0;
00370 break;
00371
00372 case 'T':
00373 buf = strptime(buf, "%H:%M:%S", tm);
00374 if (buf == 0) return 0;
00375 break;
00376
00377 case 'X':
00378 buf = strptime(buf, En_US.time_format, tm);
00379 if (buf == 0) return 0;
00380 break;
00381
00382 case 'x':
00383 buf = strptime(buf, En_US.sDate_format, tm);
00384 if (buf == 0) return 0;
00385 break;
00386
00387 case 'j':
00388 if (!isdigit(*buf)) return 0;
00389 for (i = 0; *buf != 0 && isdigit(*buf); ++buf)
00390 {
00391 i *= 10;
00392 i += *buf - '0';
00393 }
00394 if (i > 365) return 0;
00395 tm->tm_yday = i;
00396 break;
00397
00398 case 'M':
00399 case 'S':
00400 if (*buf == 0 || isspace(*buf)) break;
00401 if (!isdigit(*buf)) return 0;
00402 for (i = 0; *buf != 0 && isdigit(*buf); ++buf)
00403 {
00404 i *= 10;
00405 i += *buf - '0';
00406 }
00407 if (i > 59) return 0;
00408 if (c == 'M')
00409 tm->tm_min = i;
00410 else
00411 tm->tm_sec = i;
00412 if (*buf != 0 && isspace(*buf))
00413 while (*ptr != 0 && !isspace(*ptr)) ++ptr;
00414 break;
00415
00416 case 'H':
00417 case 'I':
00418 case 'k':
00419 case 'l':
00420 if (!isdigit(*buf)) return 0;
00421 for (i = 0; *buf != 0 && isdigit(*buf); ++buf)
00422 {
00423 i *= 10;
00424 i += *buf - '0';
00425 }
00426 if (c == 'H' || c == 'k')
00427 {if (i > 23) return 0;}
00428 else if (i > 11) return 0;
00429 tm->tm_hour = i;
00430 if (*buf != 0 && isspace(*buf))
00431 while (*ptr != 0 && !isspace(*ptr)) ++ptr;
00432 break;
00433
00434 case 'p':
00435 if (strncasecmp(buf, En_US.am_string, En_US.len_am_string) == 0)
00436 {
00437 if (tm->tm_hour > 12) return 0;
00438 if (tm->tm_hour == 12) tm->tm_hour = 0;
00439 buf += len;
00440 break;
00441 }
00442 if (strncasecmp(buf, En_US.pm_string, En_US.len_pm_string) == 0)
00443 {
00444 if (tm->tm_hour > 12) return 0;
00445 if (tm->tm_hour != 12) tm->tm_hour += 12;
00446 buf += len;
00447 break;
00448 }
00449 return 0;
00450
00451 case 'A':
00452 case 'a':
00453 for (i = 0; i < En_US.numWeekdays; ++i)
00454 {
00455 if (strncasecmp(buf, En_US.weekday_names[i],
00456 En_US.len_weekday_names[i]) == 0) break;
00457 if (strncasecmp(buf, En_US.abbrev_weekday_names[i],
00458 En_US.len_abbrev_weekday_names[i]) == 0) break;
00459 }
00460 if (i == En_US.numWeekdays) return 0;
00461 tm->tm_wday = i;
00462 buf += len;
00463 break;
00464
00465 case 'd':
00466 case 'e':
00467 if (!isdigit(*buf)) return 0;
00468 for (i = 0; *buf != 0 && isdigit(*buf); ++buf)
00469 {
00470 i *= 10;
00471 i += *buf - '0';
00472 }
00473 if (i > 31) return 0;
00474 tm->tm_mday = i;
00475 if (*buf != 0 && isspace(*buf))
00476 while (*ptr != 0 && !isspace(*ptr)) ++ptr;
00477 break;
00478
00479 case 'B':
00480 case 'b':
00481 case 'h':
00482 for (i = 0; i < En_US.numMonths; ++i)
00483 {
00484 if (strncasecmp(buf, En_US.month_names[i],
00485 En_US.len_month_names[i]) == 0) break;
00486 if (strncasecmp(buf, En_US.abbrev_month_names[i],
00487 En_US.len_abbrev_month_names[i]) == 0) break;
00488 }
00489 if (i == En_US.numMonths) return 0;
00490 tm->tm_mon = i;
00491 buf += len;
00492 break;
00493
00494 case 'm':
00495 if (!isdigit(*buf)) return 0;
00496 for (i = 0; *buf != 0 && isdigit(*buf); ++buf)
00497 {
00498 i *= 10;
00499 i += *buf - '0';
00500 }
00501 if (i < 1 || i > 12) return 0;
00502 tm->tm_mon = i - 1;
00503 if (*buf != 0 && isspace(*buf))
00504 while (*ptr != 0 && !isspace(*ptr)) ++ptr;
00505 break;
00506
00507 case 'Y':
00508 case 'y':
00509 if (*buf == 0 || isspace(*buf)) break;
00510 if (!isdigit(*buf)) return 0;
00511 for (i = 0; *buf != 0 && isdigit(*buf); ++buf)
00512 {
00513 i *= 10;
00514 i += *buf - '0';
00515 }
00516 if (c == 'Y') i -= 1900;
00517 if (i < 0) return 0;
00518 tm->tm_year = i;
00519 if (*buf != 0 && isspace(*buf))
00520 while (*ptr != 0 && !isspace(*ptr)) ++ptr;
00521 break;
00522 }
00523 }
00524
00525 return const_cast<char*>(buf);
00526 }
00527
00528 #endif
00529
00530 }
00531 }
00532