jtime.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jmisc.hpp"
  15. #include "jtime.ipp"
  16. #include "jexcept.hpp"
  17. #include "jerror.hpp"
  18. static int tzDelta = 0; // Mainly for testing, but could be used for a cache
  19. #ifndef __GNUC__
  20. #if _WIN32 //this appears to be the best way of controlling timezone information used by mktime
  21. void setUtcTZ()
  22. {
  23. _wputenv(L"TZ=UTC0UTC");
  24. _tzset();
  25. }
  26. wchar_t localTZ[80];
  27. void setLocalTZ()
  28. {
  29. _wputenv(localTZ);
  30. _tzset();
  31. }
  32. MODULE_INIT(INIT_PRIORITY_JTIME)
  33. {
  34. TIME_ZONE_INFORMATION localInfo;
  35. GetTimeZoneInformation(&localInfo);
  36. wchar_t * finger = localTZ;
  37. int biasHour = localInfo.Bias / 60;
  38. int biasMin = abs(localInfo.Bias) % 60;
  39. wcsncpy(finger, L"TZ=", 3);
  40. finger += 3;
  41. wcsncpy(finger, localInfo.StandardName, 3);
  42. finger += 3;
  43. if(biasMin)
  44. finger += swprintf(finger, L"%d:%02d", biasHour, biasMin);
  45. else
  46. finger += swprintf(finger, L"%d", biasHour);
  47. wcsncpy(finger, localInfo.DaylightName, 3);
  48. finger += 3;
  49. *finger = 0;
  50. setLocalTZ();
  51. return true;
  52. }
  53. #else //not GNU or WIN32, assume standard behaviour (untested)
  54. StringBuffer localTZ;
  55. void setUtcTZ()
  56. {
  57. localTZ.clear().append(getenv("TZ"));
  58. setenv("TZ", "UTC");
  59. }
  60. void setLocalTZ()
  61. {
  62. setenv("TZ", localTZ.str());
  63. }
  64. #endif //_WIN32
  65. Mutex timeMutex;
  66. struct tm * gmtime_r(time_t const * simple, struct tm * utc)
  67. {
  68. synchronized procedure(timeMutex);
  69. struct tm * ts = gmtime(simple);
  70. if(!ts) return NULL;
  71. memcpy(utc, ts, sizeof(struct tm));
  72. return utc;
  73. }
  74. struct tm * localtime_r(time_t const * simple, struct tm * local)
  75. {
  76. synchronized procedure(timeMutex);
  77. struct tm * ts = localtime(simple);
  78. if(!ts) return NULL;
  79. memcpy(local, ts, sizeof(struct tm));
  80. return local;
  81. }
  82. time_t timegm(struct tm * utc)
  83. {
  84. synchronized procedure(timeMutex);
  85. setUtcTZ(); //YUCK, but this is apparently standard practice where timegm is not available
  86. time_t simple = mktime(utc);
  87. setLocalTZ();
  88. return simple;
  89. }
  90. time_t timelocal(struct tm * local)
  91. {
  92. synchronized procedure(timeMutex);
  93. return mktime(local); //mktime is more common (but less descriptive) name for timelocal
  94. }
  95. #endif //__GNUC__
  96. static unsigned readDigits(char const * & str, unsigned numDigits)
  97. {
  98. unsigned ret = 0;
  99. while(numDigits--)
  100. {
  101. char c = *str++;
  102. if(!isdigit(c))
  103. throwError1(JLIBERR_BadlyFormedDateTime, str);
  104. ret = ret * 10 + (c - '0');
  105. }
  106. return ret;
  107. }
  108. static void checkChar(char const * & str, char required)
  109. {
  110. char c = *str++;
  111. if(c != required)
  112. throwError1(JLIBERR_BadlyFormedDateTime, str);
  113. }
  114. void CDateTime::setFromUtcTm(struct tm const & ts)
  115. {
  116. utc_year = ts.tm_year;
  117. utc_mon = ts.tm_mon;
  118. utc_mday = ts.tm_mday;
  119. utc_hour = ts.tm_hour;
  120. utc_min = ts.tm_min;
  121. utc_sec = ts.tm_sec;
  122. }
  123. void CDateTime::getToUtcTm(struct tm & ts) const
  124. {
  125. ts.tm_year = utc_year;
  126. ts.tm_mon = utc_mon;
  127. ts.tm_mday = utc_mday;
  128. ts.tm_hour = utc_hour;
  129. ts.tm_min = utc_min;
  130. ts.tm_sec = utc_sec;
  131. ts.tm_isdst = 0;
  132. }
  133. void CDateTime::deserialize(MemoryBuffer &src)
  134. {
  135. src.read(utc_year).read(utc_mon).read(utc_mday).read(utc_hour).read(utc_min).read(utc_sec).read(nanosec);
  136. utc_year -= 1900;
  137. utc_mon -= 1;
  138. }
  139. void CDateTime::serialize(MemoryBuffer &dst) const
  140. {
  141. short year = 1900+utc_year;
  142. byte mon = 1+utc_mon;
  143. dst.append(year).append(mon).append(utc_mday).append(utc_hour).append(utc_min).append(utc_sec).append(nanosec);
  144. }
  145. // See http://www.isthe.com/chongo/tech/comp/fnv/index.html and eclrtl.cpp
  146. #define FNV_64_PRIME I64C(0x100000001b3U)
  147. #define APPLY_FNV64(hval, next) { hval *= FNV_64_PRIME; hval ^= next; }
  148. hash64_t CDateTime::getHash(hash64_t hash) const
  149. {
  150. APPLY_FNV64(hash, utc_sec);
  151. APPLY_FNV64(hash, utc_min);
  152. APPLY_FNV64(hash, utc_hour);
  153. APPLY_FNV64(hash, utc_mday);
  154. APPLY_FNV64(hash, utc_mon);
  155. APPLY_FNV64(hash, utc_year);
  156. APPLY_FNV64(hash, nanosec);
  157. return hash;
  158. }
  159. void CDateTime::clear()
  160. {
  161. utc_sec = 0;
  162. utc_min = 0;
  163. utc_hour = 0;
  164. utc_mday = 1;
  165. utc_mon = 0;
  166. utc_year = 0;
  167. nanosec = 0;
  168. }
  169. void CDateTime::set(CDateTime const & other)
  170. {
  171. utc_sec = other.utc_sec;
  172. utc_min = other.utc_min;
  173. utc_hour = other.utc_hour;
  174. utc_mday = other.utc_mday;
  175. utc_mon = other.utc_mon;
  176. utc_year = other.utc_year;
  177. nanosec = other.nanosec;
  178. }
  179. void CDateTime::set(time_t simple)
  180. {
  181. struct tm ts;
  182. gmtime_r(&simple, &ts);
  183. setFromUtcTm(ts);
  184. }
  185. void CDateTime::setString(char const * str, char const * * end, bool local)
  186. {
  187. if (!str||!*str) {
  188. clear();
  189. return;
  190. }
  191. unsigned year = readDigits(str, 4);
  192. checkChar(str, '-');
  193. unsigned month = readDigits(str, 2);
  194. checkChar(str, '-');
  195. unsigned day = readDigits(str, 2);
  196. checkChar(str, 'T');
  197. unsigned hour = readDigits(str, 2);
  198. checkChar(str, ':');
  199. unsigned minute = readDigits(str, 2);
  200. checkChar(str, ':');
  201. unsigned sec = readDigits(str, 2);
  202. unsigned nano = 0;
  203. if(*str == '.')
  204. {
  205. unsigned digits;
  206. for(digits = 0; digits < 9; digits++)
  207. {
  208. char c = *++str;
  209. if(!isdigit(c)) break;
  210. nano = nano * 10 + (c - '0');
  211. }
  212. while(digits++<9)
  213. nano *= 10;
  214. }
  215. if(end) *end = str;
  216. set(year, month, day, hour, minute, sec, nano, local);
  217. }
  218. void CDateTime::setDateString(char const * str, char const * * end)
  219. {
  220. unsigned year = readDigits(str, 4);
  221. checkChar(str, '-');
  222. unsigned month = readDigits(str, 2);
  223. checkChar(str, '-');
  224. unsigned day = readDigits(str, 2);
  225. if(end) *end = str;
  226. set(year, month, day, 0, 0, 0, 0, false);
  227. }
  228. void CDateTime::setTimeString(char const * str, char const * * end, bool local)
  229. {
  230. unsigned year;
  231. unsigned month;
  232. unsigned day;
  233. getDate(year, month, day, false);
  234. unsigned hour = readDigits(str, 2);
  235. checkChar(str, ':');
  236. unsigned minute = readDigits(str, 2);
  237. checkChar(str, ':');
  238. unsigned sec = readDigits(str, 2);
  239. unsigned nano = 0;
  240. if(*str == '.')
  241. {
  242. unsigned digits;
  243. for(digits = 0; digits < 9; digits++)
  244. {
  245. char c = *++str;
  246. if(!isdigit(c)) break;
  247. nano = nano * 10 + (c - '0');
  248. }
  249. while(digits++<9)
  250. nano *= 10;
  251. }
  252. if(end) *end = str;
  253. set(year, month, day, hour, minute, sec, nano, local);
  254. }
  255. void CDateTime::set(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned minute, unsigned second, unsigned nano, bool local)
  256. {
  257. if(local)
  258. {
  259. struct tm local;
  260. local.tm_year = year - 1900;
  261. local.tm_mon = month - 1;
  262. local.tm_mday = day;
  263. local.tm_hour = hour;
  264. local.tm_min = minute;
  265. local.tm_sec = second;
  266. local.tm_isdst = -1;
  267. time_t simple = timelocal(&local);
  268. set(simple);
  269. }
  270. else
  271. {
  272. utc_year = year - 1900;
  273. utc_mon = month - 1;
  274. utc_mday = day;
  275. utc_hour = hour;
  276. utc_min = minute;
  277. utc_sec = second;
  278. }
  279. nanosec = nano;
  280. }
  281. void CDateTime::setDate(unsigned year, unsigned month, unsigned day)
  282. {
  283. set(year, month, day, 0, 0, 0, 0, false);
  284. }
  285. void CDateTime::setTime(unsigned hour, unsigned minute, unsigned second, unsigned nano, bool local)
  286. {
  287. unsigned year;
  288. unsigned month;
  289. unsigned day;
  290. getDate(year, month, day, false);
  291. set(year, month, day, hour, minute, second, nano, local);
  292. }
  293. //FILETIME is a large integer that represents the number of 100 nanosecond
  294. //intervals since January 1, 1601 (UTC), also known as a FILETIME value.
  295. void CDateTime::setFromFILETIME(__int64 fileTime)
  296. {
  297. __int64 secsAfterADEpoch = fileTime / 10000000;
  298. __int64 AD2Unix = ((1970-1601) * 365 - 3 + ((1970-1601)/4) ) * (__int64)86400;
  299. set(secsAfterADEpoch - AD2Unix);
  300. }
  301. void CDateTime::setNow()
  302. {
  303. time_t simple;
  304. time(&simple);
  305. set(simple);
  306. }
  307. void CDateTime::adjustTime(int deltaMins)
  308. {
  309. time_t simple = getSimple();
  310. simple += deltaMins * 60;
  311. set(simple);
  312. }
  313. void CDateTime::getDate(unsigned & year, unsigned & month, unsigned & day, bool local) const
  314. {
  315. if(local)
  316. {
  317. time_t simple = getSimple();
  318. struct tm local;
  319. localtime_r(&simple, &local);
  320. year = local.tm_year + 1900;
  321. month = local.tm_mon + 1;
  322. day = local.tm_mday;
  323. }
  324. else
  325. {
  326. year = utc_year + 1900;
  327. month = utc_mon + 1;
  328. day = utc_mday;
  329. }
  330. }
  331. void CDateTime::getTime(unsigned & hour, unsigned & minute, unsigned & second, unsigned & nano, bool local) const
  332. {
  333. if(local)
  334. {
  335. time_t simple = getSimple();
  336. struct tm local;
  337. localtime_r(&simple, &local);
  338. hour = local.tm_hour;
  339. minute = local.tm_min;
  340. second = local.tm_sec;
  341. }
  342. else
  343. {
  344. hour = utc_hour;
  345. minute = utc_min;
  346. second = utc_sec;
  347. }
  348. nano = nanosec;
  349. }
  350. time_t CDateTime::getSimple() const
  351. {
  352. struct tm ts;
  353. getToUtcTm(ts);
  354. return timegm(&ts);
  355. }
  356. StringBuffer & CDateTime::getString(StringBuffer & str, bool local) const
  357. {
  358. if(isNull()) return str;
  359. char buff[64]; // allow extra for invalid dates
  360. char * finger = buff;
  361. if(local)
  362. {
  363. time_t simple = getSimple();
  364. struct tm local;
  365. localtime_r(&simple, &local);
  366. finger += sprintf(finger, "%04d-%02d-%02dT%02d:%02d:%02d", local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
  367. }
  368. else
  369. finger += sprintf(finger, "%04d-%02d-%02dT%02d:%02d:%02d", utc_year+1900, utc_mon+1, utc_mday, utc_hour, utc_min, utc_sec);
  370. if(nanosec) finger += sprintf(finger, ".%06u", nanosec/1000);
  371. return str.append(buff);
  372. }
  373. StringBuffer & CDateTime::getDateString(StringBuffer & str, bool local) const
  374. {
  375. if(isNull()) return str;
  376. char buff[64]; // allow extra for invalid dates
  377. if(local)
  378. {
  379. time_t simple = getSimple();
  380. struct tm local;
  381. localtime_r(&simple, &local);
  382. sprintf(buff, "%04d-%02d-%02d", local.tm_year+1900, local.tm_mon+1, local.tm_mday);
  383. }
  384. else
  385. sprintf(buff, "%04d-%02d-%02d", utc_year+1900, utc_mon+1, utc_mday);
  386. return str.append(buff);
  387. }
  388. StringBuffer & CDateTime::getTimeString(StringBuffer & str, bool local) const
  389. {
  390. if(isNull()) return str;
  391. char buff[64]; // allow extra for invalid dates
  392. char * finger = buff;
  393. if(local)
  394. {
  395. time_t simple = getSimple();
  396. struct tm local;
  397. localtime_r(&simple, &local);
  398. finger += sprintf(finger, "%02d:%02d:%02d", local.tm_hour, local.tm_min, local.tm_sec);
  399. }
  400. else
  401. finger += sprintf(finger, "%02d:%02d:%02d", utc_hour, utc_min, utc_sec);
  402. if(nanosec) finger += sprintf(finger, ".%06u", nanosec/1000);
  403. return str.append(buff);
  404. }
  405. bool CDateTime::isNull() const
  406. {
  407. if(utc_year || utc_mon || (utc_mday-1) || utc_hour || utc_min || utc_sec || nanosec)
  408. return false;
  409. return true;
  410. }
  411. bool CDateTime::equals(CDateTime const & cdt, bool compareNanosec) const
  412. {
  413. time_t thisSimple = getSimple();
  414. time_t thatSimple = cdt.getSimple();
  415. return ((thisSimple == thatSimple) && ((compareNanosec) ? (nanosec == cdt.nanosec) : true));
  416. }
  417. int CDateTime::compare(CDateTime const & cdt, bool compareNanosec) const
  418. {
  419. time_t thisSimple = getSimple();
  420. time_t thatSimple = cdt.getSimple();
  421. if(thisSimple != thatSimple) return ((thisSimple > thatSimple) ? +1 : -1);
  422. if(compareNanosec && (nanosec != cdt.nanosec)) return ((nanosec > cdt.nanosec) ? +1 : -1);
  423. return 0;
  424. }
  425. int CDateTime::compareDate(CDateTime const & cdt) const
  426. {
  427. if(utc_year != cdt.utc_year) return ((utc_year > cdt.utc_year) ? +1 : -1);
  428. if(utc_mon != cdt.utc_mon) return ((utc_mon > cdt.utc_mon) ? +1 : -1);
  429. if(utc_mday != cdt.utc_mday) return ((utc_mday > cdt.utc_mday) ? +1 : -1);
  430. return 0;
  431. }
  432. int CDateTime::queryUtcToLocalDelta() const
  433. {
  434. struct tm ts;
  435. getToUtcTm(ts);
  436. time_t correct = timegm(&ts);
  437. time_t shifted = timelocal(&ts);
  438. return ((int)(correct - shifted))/60;
  439. }
  440. //---------------------------------------------------------------------------
  441. CScmDateTime::CScmDateTime()
  442. {
  443. utcToLocalDelta = 0;
  444. }
  445. IStringVal & CScmDateTime::getString(IStringVal & str) const
  446. {
  447. StringBuffer temp;
  448. CDateTime local(cdt);
  449. local.adjustTime(utcToLocalDelta);
  450. local.getString(temp);
  451. if (utcToLocalDelta == 0)
  452. temp.append("Z");
  453. else
  454. {
  455. int value = utcToLocalDelta;
  456. if (value > 0)
  457. temp.append('+');
  458. else
  459. {
  460. value = -value;
  461. temp.append('-');
  462. }
  463. temp.appendf("%02d:%02d", value / 60, value % 60);
  464. }
  465. str.set(temp.str());
  466. return str;
  467. }
  468. int CScmDateTime::compare(const IJlibConstDateTime & other) const
  469. {
  470. unsigned year, month, day, hour, min, sec, nanosec;
  471. other.getGmtDate(year, month, day);
  472. other.getGmtTime(hour, min, sec, nanosec);
  473. CDateTime otherCDT;
  474. otherCDT.set(year, month, day, hour, min, sec, nanosec);
  475. return cdt.compare(otherCDT);
  476. }
  477. IStringVal & CScmDateTime::getDateString(IStringVal & str) const
  478. {
  479. StringBuffer temp;
  480. CDateTime local(cdt);
  481. local.adjustTime(utcToLocalDelta);
  482. local.getDateString(temp);
  483. str.set(temp.str());
  484. return str;
  485. }
  486. IStringVal & CScmDateTime::getTimeString(IStringVal & str) const
  487. {
  488. StringBuffer temp;
  489. CDateTime local(cdt);
  490. local.adjustTime(utcToLocalDelta);
  491. local.getTimeString(temp);
  492. str.set(temp.str());
  493. return str;
  494. }
  495. void CScmDateTime::getDate(unsigned & _year, unsigned & _month, unsigned & _day) const
  496. {
  497. CDateTime local(cdt);
  498. local.adjustTime(utcToLocalDelta);
  499. local.getDate(_year, _month, _day);
  500. }
  501. void CScmDateTime::getTime(unsigned & _hour, unsigned & _min, unsigned & _sec, unsigned & _nanosec, int & localToGmtDelta) const
  502. {
  503. CDateTime local(cdt);
  504. local.adjustTime(utcToLocalDelta);
  505. local.getTime(_hour, _min, _sec, _nanosec);
  506. localToGmtDelta = -utcToLocalDelta;
  507. }
  508. IStringVal & CScmDateTime::getGmtString(IStringVal & str) const
  509. {
  510. StringBuffer temp;
  511. str.set(cdt.getString(temp).str());
  512. return str;
  513. }
  514. IStringVal & CScmDateTime::getGmtDateString(IStringVal & str) const
  515. {
  516. StringBuffer temp;
  517. str.set(cdt.getDateString(temp).str());
  518. return str;
  519. }
  520. IStringVal & CScmDateTime::getGmtTimeString(IStringVal & str) const
  521. {
  522. StringBuffer temp;
  523. str.set(cdt.getTimeString(temp).str());
  524. return str;
  525. }
  526. void CScmDateTime::getGmtDate(unsigned & _year, unsigned & _month, unsigned & _day) const
  527. {
  528. cdt.getDate(_year, _month, _day);
  529. }
  530. void CScmDateTime::getGmtTime(unsigned & _hour, unsigned & _min, unsigned & _sec, unsigned & _nanosec) const
  531. {
  532. cdt.getTime(_hour, _min, _sec, _nanosec);
  533. }
  534. IStringVal & CScmDateTime::getLocalString(IStringVal & str) const
  535. {
  536. StringBuffer temp;
  537. str.set(cdt.getString(temp, true).str());
  538. return str;
  539. }
  540. IStringVal & CScmDateTime::getLocalDateString(IStringVal & str) const
  541. {
  542. StringBuffer temp;
  543. str.set(cdt.getDateString(temp, true).str());
  544. return str;
  545. }
  546. IStringVal & CScmDateTime::getLocalTimeString(IStringVal & str) const
  547. {
  548. StringBuffer temp;
  549. str.set(cdt.getTimeString(temp, true).str());
  550. return str;
  551. }
  552. void CScmDateTime::getLocalDate(unsigned & _year, unsigned & _month, unsigned & _day) const
  553. {
  554. cdt.getDate(_year, _month, _day, true);
  555. }
  556. void CScmDateTime::getLocalTime(unsigned & _hour, unsigned & _min, unsigned & _sec, unsigned & _nanosec) const
  557. {
  558. cdt.getTime(_hour, _min, _sec, _nanosec, true);
  559. }
  560. void CScmDateTime::setString(const char * pstr)
  561. {
  562. char const * end;
  563. cdt.setString(pstr, &end, false);
  564. char sign = *end;
  565. if (toupper(sign) == 'Z')
  566. {
  567. utcToLocalDelta = 0;
  568. end++;
  569. }
  570. else if ((sign == '-') || (sign == '+'))
  571. {
  572. end++;
  573. int delta = readDigits(end, 2);
  574. if (*end++ != ':')
  575. throwError1(JLIBERR_BadlyFormedDateTime, pstr);
  576. delta = delta * 60 + readDigits(end, 2);
  577. if (sign == '-')
  578. delta = -delta;
  579. utcToLocalDelta = delta;
  580. cdt.adjustTime(-delta);
  581. }
  582. if (*end != 0)
  583. throwError1(JLIBERR_BadlyFormedDateTime, pstr);
  584. }
  585. void CScmDateTime::setDateTime(unsigned _year, unsigned _month, unsigned _day, unsigned _hour, unsigned _min, unsigned _sec, unsigned _nanosec, int localToGmtDelta)
  586. {
  587. utcToLocalDelta = -localToGmtDelta;
  588. cdt.set(_year, _month, _day, _hour, _min, _sec, _nanosec);
  589. cdt.adjustTime(localToGmtDelta);
  590. }
  591. void CScmDateTime::setGmtString(const char * pstr)
  592. {
  593. utcToLocalDelta = 0;
  594. cdt.setString(pstr);
  595. }
  596. void CScmDateTime::setGmtDateString(const char * pstr)
  597. {
  598. utcToLocalDelta = 0;
  599. cdt.setDateString(pstr);
  600. }
  601. void CScmDateTime::setGmtTimeString(const char * pstr)
  602. {
  603. utcToLocalDelta = 0;
  604. cdt.setTimeString(pstr);
  605. }
  606. void CScmDateTime::setGmtDate(unsigned _year, unsigned _month, unsigned _day)
  607. {
  608. utcToLocalDelta = 0;
  609. cdt.setDate(_year, _month, _day);
  610. }
  611. void CScmDateTime::setGmtTime(unsigned _hour, unsigned _min, unsigned _sec, unsigned _nanosec)
  612. {
  613. utcToLocalDelta = 0;
  614. cdt.setTime(_hour, _min, _sec, _nanosec);
  615. }
  616. void CScmDateTime::setLocalString(const char * pstr)
  617. {
  618. cdt.setString(pstr, NULL, true);
  619. utcToLocalDelta = cdt.queryUtcToLocalDelta();
  620. }
  621. void CScmDateTime::setLocalDateString(const char * pstr)
  622. {
  623. cdt.setDateString(pstr, NULL);
  624. utcToLocalDelta = cdt.queryUtcToLocalDelta();
  625. }
  626. void CScmDateTime::setLocalTimeString(const char * pstr)
  627. {
  628. cdt.setTimeString(pstr, NULL, true);
  629. utcToLocalDelta = cdt.queryUtcToLocalDelta();
  630. }
  631. void CScmDateTime::setLocalDate(unsigned _year, unsigned _month, unsigned _day)
  632. {
  633. cdt.setDate(_year, _month, _day);
  634. utcToLocalDelta = cdt.queryUtcToLocalDelta();
  635. }
  636. void CScmDateTime::setLocalTime(unsigned _hour, unsigned _min, unsigned _sec, unsigned _nanosec)
  637. {
  638. cdt.setTime(_hour, _min, _sec, _nanosec, true);
  639. utcToLocalDelta = cdt.queryUtcToLocalDelta();
  640. }
  641. void CScmDateTime::setNow()
  642. {
  643. cdt.setNow();
  644. }
  645. void CScmDateTime::setSimpleGmt(time_t simple)
  646. {
  647. cdt.set(simple);
  648. utcToLocalDelta = 0;
  649. }
  650. void CScmDateTime::setSimpleLocal(time_t simple)
  651. {
  652. cdt.set(simple);
  653. utcToLocalDelta = cdt.queryUtcToLocalDelta();
  654. }
  655. IJlibDateTime * createDateTime()
  656. {
  657. return new CScmDateTime;
  658. }
  659. IJlibDateTime * createDateTimeNow()
  660. {
  661. CScmDateTime * dt = new CScmDateTime;
  662. dt->setNow();
  663. return dt;
  664. }
  665. static bool isLeapYear (unsigned yr)
  666. {
  667. return (yr%400==0)||((yr%4==0)&&(yr%100!=0));
  668. }
  669. static unsigned daysInMonth(unsigned y, unsigned m)
  670. {
  671. unsigned int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  672. if ((m==2)&&isLeapYear(y))
  673. return 29;
  674. if(m < 1 || m > 12)
  675. throw MakeStringException(0, "month should between 1 and 12");
  676. return days[m - 1];
  677. }
  678. static unsigned dayOfWeek(unsigned y, unsigned m, unsigned d)
  679. {
  680. if (m < 3) {
  681. m += 13;
  682. y--;
  683. }
  684. else
  685. m++;
  686. return (d+26*m/10+y+y/4-y/100+y/400+6)%7;
  687. }
  688. static unsigned decodeDay(const char *day)
  689. { // not this uses sun as 0
  690. if (strlen(day)>=3) {
  691. const char *p="sunmontuewedthufrisat";
  692. for (unsigned i=0;i<7;i++) {
  693. if (memicmp(p,day,3)==0)
  694. return i;
  695. p += 3;
  696. }
  697. }
  698. return NotFound;
  699. }
  700. static unsigned decodeMon(const char *mon)
  701. {
  702. if (strlen(mon)>=3) {
  703. const char *p="janfebmaraprmayjunjulaugsepoctnovdec";
  704. for (unsigned i=1;i<=12;i++) {
  705. if (memicmp(p,mon,3)==0)
  706. return i;
  707. p += 3;
  708. }
  709. }
  710. return NotFound;
  711. }
  712. static void carryTimeInc(unsigned &yr, unsigned &mon, unsigned &dy, unsigned &hr, unsigned &min)
  713. {
  714. hr += (min/60);
  715. min %= 60;
  716. dy += (hr/24);
  717. hr %= 24;
  718. if (mon==0)
  719. mon++;
  720. if (dy==0)
  721. dy++;
  722. if (mon<=12) {
  723. if (dy<=daysInMonth(yr,mon))
  724. return;
  725. }
  726. loop {
  727. yr += (mon-1)/12;
  728. mon = (mon-1)%12+1;
  729. unsigned dinm = daysInMonth(yr,mon);
  730. if (dy<=dinm)
  731. break;
  732. mon++;
  733. dy -= dinm;
  734. }
  735. }
  736. inline const char *getnum(const char *s, unsigned &n,unsigned first,unsigned last)
  737. {
  738. // assumes first char is digit
  739. n = *s-'0';
  740. s++;
  741. while (isdigit(*s)) {
  742. n = n*10+(*s-'0');
  743. s++;
  744. }
  745. if (n<first)
  746. n = first;
  747. else if (n>last)
  748. n = (n-first)%(last-first+1)+first; // bit over the top but does sunday as 7
  749. return s;
  750. }
  751. inline const char *getnumorname(const char *s, unsigned &n,unsigned first,unsigned last)
  752. {
  753. n = NotFound;
  754. if (isdigit(*s))
  755. return getnum(s,n,first,last);
  756. if (last==6) // dow
  757. n = decodeDay(s);
  758. else if (last==12) // mon
  759. n = decodeMon(s);
  760. if (n!=NotFound)
  761. s+=3;
  762. return s;
  763. }
  764. static int cmpval(unsigned const *a,unsigned const *b)
  765. {
  766. if (*a>*b) return 1;
  767. if (*a<*b) return -1;
  768. return 0;
  769. }
  770. static const char *parseCronItem(const char *s,UnsignedArray &a,unsigned first,unsigned last)
  771. {
  772. a.kill();
  773. unsigned n;
  774. bool added;
  775. if (s) {
  776. if (*s=='*') {
  777. s++;
  778. if (*s=='/') {
  779. s++;
  780. if (isdigit(*s)) {
  781. s = getnum(s,n,first,last);
  782. if (n)
  783. for (unsigned i=first;i<=last;i+=n)
  784. a.bAdd(i,cmpval,added);
  785. }
  786. }
  787. }
  788. else {
  789. loop {
  790. s = getnumorname(s,n,first,last);
  791. if (n!=NotFound) {
  792. if (*s=='-') { // range
  793. s++;
  794. unsigned n2;
  795. s = getnumorname(s,n2,first,last);
  796. if (n2==NotFound)
  797. n2 = last;
  798. unsigned inc = 1;
  799. if (*s=='/') { // inc
  800. s++;
  801. if (isdigit(*s))
  802. s = getnum(s,inc,1,last);
  803. }
  804. if (n <= n2)
  805. {
  806. for (; n<=n2; n+=inc)
  807. a.bAdd(n,cmpval,added);
  808. }
  809. else
  810. {
  811. unsigned idx;
  812. for (idx=n; idx<=last; idx+=inc)
  813. a.bAdd(idx,cmpval,added);
  814. for (idx-=(last-first+1); idx<=n2; idx+=inc)
  815. a.bAdd(idx,cmpval,added);
  816. }
  817. }
  818. else
  819. a.bAdd(n,cmpval,added);
  820. }
  821. else if (*s==',')
  822. s++;
  823. else
  824. break;
  825. }
  826. }
  827. while (isspace(*s))
  828. s++;
  829. }
  830. return s;
  831. }
  832. const char *CCronAtSchedule::set(const char *spec)
  833. {
  834. if (spec)
  835. while (isspace(*spec))
  836. spec++;
  837. spec = parseCronItem(spec,minutes,0,59);
  838. spec = parseCronItem(spec,hours,0,23);
  839. spec = parseCronItem(spec,days,1,31);
  840. spec = parseCronItem(spec,months,1,12);
  841. return parseCronItem(spec,dows,0,6);
  842. }
  843. bool CCronAtSchedule::match(UnsignedArray &a,unsigned v,unsigned &next)
  844. {
  845. if (a.ordinality()==0) {
  846. next = v;
  847. return true;
  848. }
  849. ForEachItemIn(i,a) {
  850. unsigned n = a.item(i);
  851. if (n>=v) {
  852. next = n;
  853. return true;
  854. }
  855. }
  856. return false;
  857. }
  858. bool CCronAtSchedule::matchDay(unsigned yr, unsigned mon, unsigned dy, unsigned &nextdy)
  859. {
  860. // first find matching day
  861. unsigned d=0;
  862. unsigned dinm=daysInMonth(yr,mon);
  863. if (days.ordinality()==0) {
  864. if (dows.ordinality()==0) {
  865. nextdy = dy;
  866. return true;
  867. }
  868. }
  869. else {
  870. ForEachItemIn(i,days) {
  871. unsigned d1 = days.item(i);
  872. if (d1>dinm)
  873. break;
  874. if (d1>=dy) {
  875. d = d1;
  876. break;
  877. }
  878. }
  879. }
  880. if (dows.ordinality()!=0) {
  881. unsigned dow = dayOfWeek(yr,mon,dy);
  882. ForEachItemIn(i,dows) {
  883. unsigned dw = dows.item(i);
  884. unsigned d2 = dy+(dw+7-dow)%7;
  885. if ((d2<=dinm)&&((d==0)||(d2<d)))
  886. d = d2;
  887. }
  888. }
  889. if (d!=0) {
  890. nextdy = d;
  891. return true;
  892. }
  893. return false;
  894. }
  895. void CCronAtSchedule::next(const CDateTime &fromdt, CDateTime &nextdt, bool greater)
  896. {
  897. unsigned hr;
  898. unsigned min;
  899. unsigned sec;
  900. unsigned nano;
  901. fromdt.getTime(hr, min, sec, nano);
  902. sec = 0;
  903. nano = 0;
  904. unsigned yr;
  905. unsigned mon;
  906. unsigned dy;
  907. fromdt.getDate(yr, mon, dy);
  908. if (greater)
  909. min++;
  910. for (unsigned i=0;i<60*24*12;i++) { // this is just a catch to stop impossible dates infinite looping
  911. carryTimeInc(yr, mon, dy, hr, min);
  912. unsigned nextmon;
  913. if (!match(months,mon,nextmon)) {
  914. yr++;
  915. hr = 0;
  916. min = 0;
  917. dy = 1;
  918. mon = months.item(0);
  919. continue;
  920. }
  921. if (nextmon!=mon) {
  922. mon = nextmon;
  923. dy = 1;
  924. hr = 0;
  925. min = 0;
  926. }
  927. unsigned nextdy;
  928. if (!matchDay(yr,mon,dy,nextdy)) {
  929. hr = 0;
  930. min = 0;
  931. mon++;
  932. dy = 1;
  933. continue;
  934. }
  935. if (nextdy!=dy) {
  936. hr = 0;
  937. min = 0;
  938. dy = nextdy;
  939. }
  940. unsigned nexthr;
  941. if (!match(hours,hr,nexthr)) {
  942. min = 0;
  943. dy++;
  944. hr = 0;
  945. continue;
  946. }
  947. if (nexthr!=hr) {
  948. min = 0;
  949. hr = nexthr;
  950. }
  951. unsigned nextmin;
  952. if (!match(minutes,min,nextmin)) {
  953. hr++;
  954. min = 0;
  955. continue;
  956. }
  957. min = nextmin;
  958. break;
  959. }
  960. nextdt.set(yr,mon,dy,hr,min,sec,nano);
  961. }
  962. class CronTableItem
  963. {
  964. public:
  965. CronTableItem(CronTableItem * _prev, CronTableItem * _next, char const * spec, char const * _tag, bool inframe) : prev(_prev), next(_next), tag(_tag), markDelete(false), markNew(inframe)
  966. {
  967. char const * specend = cron.set(spec);
  968. if((specend-spec) != strlen(spec))
  969. throw MakeStringException(0, "Bad cron spec %s", spec);
  970. }
  971. CronTableItem * prev;
  972. CronTableItem * next;
  973. StringAttr tag;
  974. CCronAtSchedule cron;
  975. bool markDelete;
  976. bool markNew;
  977. };
  978. class CCronTable : public CInterface, implements ICronTable
  979. {
  980. private:
  981. class XFrame : public CInterface, implements ICronTable::Transaction
  982. {
  983. public:
  984. XFrame(CCronTable * _owner) : owner(_owner) {}
  985. ~XFrame() { CriticalBlock block(owner->crit); dorollback(); owner->hasframe = false; }
  986. IMPLEMENT_IINTERFACE;
  987. virtual void add(char const * spec, char const * tag)
  988. {
  989. CriticalBlock block(owner->crit);
  990. owner->doadd(spec, tag, true);
  991. }
  992. virtual unsigned remove(char const * tag)
  993. {
  994. CriticalBlock block(owner->crit);
  995. CronTableItem * finger = owner->head;
  996. unsigned count = 0;
  997. while(finger)
  998. {
  999. if(strcmp(finger->tag.get(), tag)==0)
  1000. {
  1001. finger->markDelete = true;
  1002. count++;
  1003. }
  1004. finger = finger->next;
  1005. }
  1006. return count;
  1007. }
  1008. virtual unsigned unremove(char const * tag)
  1009. {
  1010. CriticalBlock block(owner->crit);
  1011. CronTableItem * finger = owner->head;
  1012. unsigned count = 0;
  1013. while(finger)
  1014. {
  1015. if(strcmp(finger->tag.get(), tag)==0)
  1016. {
  1017. finger->markDelete = false;
  1018. count++;
  1019. }
  1020. finger = finger->next;
  1021. }
  1022. return count;
  1023. }
  1024. virtual void removeall()
  1025. {
  1026. CriticalBlock block(owner->crit);
  1027. CronTableItem * finger = owner->head;
  1028. while(finger)
  1029. {
  1030. finger->markDelete = true;
  1031. finger = finger->next;
  1032. }
  1033. }
  1034. virtual void commit()
  1035. {
  1036. CriticalBlock block(owner->crit);
  1037. CronTableItem * finger = owner->head;
  1038. while(finger)
  1039. {
  1040. CronTableItem * next = finger->next;
  1041. if(finger->markDelete)
  1042. owner->doremove(finger);
  1043. else
  1044. finger->markNew = false;
  1045. finger = next;
  1046. }
  1047. }
  1048. virtual void rollback() { CriticalBlock block(owner->crit); dorollback(); }
  1049. private:
  1050. void dorollback()
  1051. {
  1052. CronTableItem * finger = owner->head;
  1053. while(finger)
  1054. {
  1055. CronTableItem * next = finger->next;
  1056. if(finger->markNew)
  1057. owner->doremove(finger);
  1058. else
  1059. finger->markDelete = false;
  1060. finger = next;
  1061. }
  1062. }
  1063. private:
  1064. CCronTable * owner;
  1065. };
  1066. public:
  1067. CCronTable() : head(NULL), tail(NULL), hasframe(false) {}
  1068. ~CCronTable()
  1069. {
  1070. kill();
  1071. }
  1072. IMPLEMENT_IINTERFACE;
  1073. virtual void add(char const * spec, char const * tag)
  1074. {
  1075. CriticalBlock block(crit);
  1076. doadd(spec, tag, false);
  1077. }
  1078. virtual unsigned remove(char const * tag)
  1079. {
  1080. CriticalBlock block(crit);
  1081. CronTableItem * finger = head;
  1082. unsigned count = 0;
  1083. while(finger)
  1084. {
  1085. if(hasframe)
  1086. {
  1087. while(finger && finger->markNew) finger = finger->next;
  1088. if(!finger) break;
  1089. }
  1090. CronTableItem * next = finger->next;
  1091. if(strcmp(finger->tag.get(), tag)==0)
  1092. {
  1093. doremove(finger);
  1094. count++;
  1095. }
  1096. finger = next;
  1097. }
  1098. return count;
  1099. }
  1100. virtual void removeall()
  1101. {
  1102. CriticalBlock block(crit);
  1103. if(hasframe)
  1104. {
  1105. CronTableItem * finger = head;
  1106. while(finger)
  1107. {
  1108. CronTableItem * next = finger->next;
  1109. if(!finger->markNew)
  1110. doremove(finger);
  1111. finger = next;
  1112. }
  1113. }
  1114. else
  1115. {
  1116. kill();
  1117. }
  1118. }
  1119. virtual unsigned next(CDateTime const & fromdt, CDateTime & nextdt, StringArray & tags)
  1120. {
  1121. CriticalBlock block(crit);
  1122. tags.kill();
  1123. if(!head) return 0;
  1124. head->cron.next(fromdt, nextdt, true);
  1125. tags.append(head->tag.get());
  1126. CronTableItem * finger = head->next;
  1127. CDateTime fingerdt;
  1128. while(finger)
  1129. {
  1130. if(hasframe)
  1131. {
  1132. while(finger && finger->markNew) finger = finger->next;
  1133. if(!finger) break;
  1134. }
  1135. finger->cron.next(fromdt, fingerdt, true);
  1136. int cmp = fingerdt.compare(nextdt);
  1137. if(cmp<=0)
  1138. {
  1139. if(cmp<0)
  1140. {
  1141. nextdt.set(fingerdt);
  1142. tags.kill();
  1143. }
  1144. tags.append(finger->tag.get());
  1145. }
  1146. finger = finger->next;
  1147. }
  1148. return tags.ordinality();
  1149. }
  1150. virtual Transaction * getTransactionFrame()
  1151. {
  1152. CriticalBlock block(crit);
  1153. if(hasframe) return NULL;
  1154. hasframe = true;
  1155. return new XFrame(this);
  1156. }
  1157. private:
  1158. void kill()
  1159. {
  1160. CronTableItem * del;
  1161. while(head)
  1162. {
  1163. del = head;
  1164. head = head->next;
  1165. delete del;
  1166. }
  1167. head = tail = NULL;
  1168. }
  1169. void doadd(char const * spec, char const * tag, bool inframe)
  1170. {
  1171. CronTableItem * newtail = new CronTableItem(tail, NULL, spec, tag, inframe);
  1172. if(tail)
  1173. {
  1174. tail->next = newtail;
  1175. tail = newtail;
  1176. }
  1177. else
  1178. {
  1179. head = tail = newtail;
  1180. }
  1181. }
  1182. void doremove(CronTableItem * finger)
  1183. {
  1184. if(finger->prev)
  1185. finger->prev->next = finger->next;
  1186. else
  1187. head = finger->next;
  1188. if(finger->next)
  1189. finger->next->prev = finger->prev;
  1190. else
  1191. tail = finger->prev;
  1192. delete finger;
  1193. }
  1194. private:
  1195. friend class XFrame;
  1196. CronTableItem * head;
  1197. CronTableItem * tail;
  1198. CriticalSection crit;
  1199. bool hasframe;
  1200. };
  1201. ICronTable * createCronTable() { return new CCronTable(); }
  1202. #if 0
  1203. void testTiming()
  1204. {
  1205. Owned<IJlibDateTime> ts = createDateTime();
  1206. StringAttr result;
  1207. StringAttrAdaptor ret(result);
  1208. if(timezone != -20700)
  1209. assertex(!"Please set your OS to Nepalese (Kathmandu) time to run this test");
  1210. ts->setDateTime(2001,1,1,19,56,23,0,-180);
  1211. ts->getString(ret);
  1212. assertex(strcmp(result, "2001-01-01T19:56:23+03:00") == 0);
  1213. ts->getGmtString(ret);
  1214. assertex(strcmp(result, "2001-01-01T16:56:23") == 0);
  1215. ts->getLocalString(ret);
  1216. assertex(strcmp(result, "2001-01-01T22:41:23") == 0);
  1217. ts->setDateTime(2004,2,28,23,56,23,0,180);
  1218. ts->getString(ret);
  1219. assertex(strcmp(result, "2004-02-28T23:56:23-03:00") == 0);
  1220. ts->getGmtString(ret);
  1221. assertex(strcmp(result, "2004-02-29T02:56:23") == 0);
  1222. ts->getLocalString(ret);
  1223. assertex(strcmp(result, "2004-02-29T08:41:23") == 0);
  1224. ts->setDateTime(2003,2,28,23,56,23,0,180);
  1225. ts->getString(ret);
  1226. assertex(strcmp(result, "2003-02-28T23:56:23-03:00") == 0);
  1227. ts->getGmtString(ret);
  1228. assertex(strcmp(result, "2003-03-01T02:56:23") == 0);
  1229. ts->getLocalString(ret);
  1230. assertex(strcmp(result, "2003-03-01T08:41:23") == 0);
  1231. ts->setDateTime(2004,2,28,23,56,23,0,0);
  1232. ts->getString(ret);
  1233. assertex(strcmp(result, "2004-02-28T23:56:23Z") == 0);
  1234. ts->setDateTime(1970,0,1,0,0,0,0,0);
  1235. ts->setString("2003-02-28T23:56:23-03:00");
  1236. ts->getString(ret);
  1237. assertex(strcmp(result, "2003-02-28T23:56:23-03:00") == 0);
  1238. ts->setDateTime(0,0,0,0,0,0,0,0);
  1239. ts->setString("2003-02-28T23:56:23");
  1240. ts->getString(ret);
  1241. assertex(strcmp(result, "2003-02-28T23:56:23Z") == 0);
  1242. ts->setDateTime(0,0,0,0,0,0,0,0);
  1243. ts->setString("2003-02-28T23:56:23Z");
  1244. ts->getString(ret);
  1245. assertex(strcmp(result, "2003-02-28T23:56:23Z") == 0);
  1246. ts->setDateTime(0,0,0,0,0,0,0,0);
  1247. ts->setGmtString("2003-02-28T23:56:23");
  1248. ts->getString(ret);
  1249. assertex(strcmp(result, "2003-02-28T23:56:23Z") == 0);
  1250. ts->setDateTime(0,0,0,0,0,0,0,0);
  1251. ts->setLocalString("2003-02-28T23:56:23");
  1252. ts->getString(ret);
  1253. assertex(strcmp(result, "2003-02-28T23:56:23+05:45") == 0);
  1254. ts->getLocalString(ret);
  1255. assertex(strcmp(result, "2003-02-28T23:56:23") == 0);
  1256. ts->getGmtString(ret);
  1257. assertex(strcmp(result, "2003-02-28T18:11:23") == 0);
  1258. ts->setDateTime(0,0,0,0,0,0,0,0);
  1259. ts->setLocalString("2003-07-28T23:56:23");
  1260. ts->getGmtString(ret);
  1261. assertex(strcmp(result, "2003-07-28T17:11:23") == 0);
  1262. }
  1263. void testCronTable()
  1264. {
  1265. Owned<ICronTable> crontab(createCronTable());
  1266. crontab->add("30 * * * *", "on the half hour");
  1267. crontab->add("* * * * *", "every minute");
  1268. crontab->add("*/2 * * * *", "every even minute");
  1269. crontab->add("0 * * * *", "on the hour");
  1270. crontab->add("0 0 */2 * *", "every other midnight");
  1271. crontab->add("0 2,7-9 * * *", "two, seven, eight, and nine o'clock");
  1272. CDateTime in;
  1273. CDateTime key;
  1274. CDateTime out;
  1275. StringArray tags;
  1276. unsigned ret;
  1277. in.set(2004, 12, 6, 17, 32, 30);
  1278. key.set(2004, 12, 6, 17, 33, 0);
  1279. ret = crontab->next(in, out, tags);
  1280. assertex(out == key);
  1281. assertex(ret==1);
  1282. assertex(strcmp(tags.item(0), "every minute")==0);
  1283. in.set(2004, 12, 6, 17, 33, 0);
  1284. key.set(2004, 12, 6, 17, 34, 0);
  1285. ret = crontab->next(in, out, tags);
  1286. assertex(out == key);
  1287. assertex(ret==2);
  1288. assertex(strcmp(tags.item(0), "every minute")==0);
  1289. assertex(strcmp(tags.item(1), "every even minute")==0);
  1290. in.set(2004, 12, 6, 17, 59, 0);
  1291. key.set(2004, 12, 6, 18, 0, 0);
  1292. ret = crontab->next(in, out, tags);
  1293. assertex(out == key);
  1294. assertex(ret==3);
  1295. assertex(strcmp(tags.item(0), "every minute")==0);
  1296. assertex(strcmp(tags.item(1), "every even minute")==0);
  1297. assertex(strcmp(tags.item(2), "on the hour")==0);
  1298. in.set(2004, 12, 6, 18, 29, 0);
  1299. key.set(2004, 12, 6, 18, 30, 0);
  1300. ret = crontab->next(in, out, tags);
  1301. assertex(out == key);
  1302. assertex(ret==3);
  1303. assertex(strcmp(tags.item(0), "on the half hour")==0);
  1304. assertex(strcmp(tags.item(1), "every minute")==0);
  1305. assertex(strcmp(tags.item(2), "every even minute")==0);
  1306. in.set(2004, 12, 6, 23, 59, 0);
  1307. key.set(2004, 12, 7, 0, 0, 0);
  1308. ret = crontab->next(in, out, tags);
  1309. assertex(out == key);
  1310. assertex(ret==4);
  1311. assertex(strcmp(tags.item(0), "every minute")==0);
  1312. assertex(strcmp(tags.item(1), "every even minute")==0);
  1313. assertex(strcmp(tags.item(2), "on the hour")==0);
  1314. assertex(strcmp(tags.item(3), "every other midnight")==0);
  1315. in.set(2004, 12, 7, 23, 59, 0);
  1316. key.set(2004, 12, 8, 0, 0, 0);
  1317. ret = crontab->next(in, out, tags);
  1318. assertex(out == key);
  1319. assertex(ret==3);
  1320. assertex(strcmp(tags.item(0), "every minute")==0);
  1321. assertex(strcmp(tags.item(1), "every even minute")==0);
  1322. assertex(strcmp(tags.item(2), "on the hour")==0);
  1323. in.set(2004, 12, 6, 1, 59, 0);
  1324. key.set(2004, 12, 6, 2, 0, 0);
  1325. ret = crontab->next(in, out, tags);
  1326. assertex(out == key);
  1327. assertex(ret==4);
  1328. assertex(strcmp(tags.item(0), "every minute")==0);
  1329. assertex(strcmp(tags.item(1), "every even minute")==0);
  1330. assertex(strcmp(tags.item(2), "on the hour")==0);
  1331. assertex(strcmp(tags.item(3), "two, seven, eight, and nine o'clock")==0);
  1332. in.set(2004, 12, 6, 7, 59, 0);
  1333. key.set(2004, 12, 6, 8, 0, 0);
  1334. ret = crontab->next(in, out, tags);
  1335. assertex(out == key);
  1336. assertex(ret==4);
  1337. assertex(strcmp(tags.item(0), "every minute")==0);
  1338. assertex(strcmp(tags.item(1), "every even minute")==0);
  1339. assertex(strcmp(tags.item(2), "on the hour")==0);
  1340. assertex(strcmp(tags.item(3), "two, seven, eight, and nine o'clock")==0);
  1341. crontab->remove("on the hour");
  1342. in.set(2004, 12, 6, 7, 59, 0);
  1343. key.set(2004, 12, 6, 8, 0, 0);
  1344. ret = crontab->next(in, out, tags);
  1345. assertex(out == key);
  1346. assertex(ret==3);
  1347. assertex(strcmp(tags.item(0), "every minute")==0);
  1348. assertex(strcmp(tags.item(1), "every even minute")==0);
  1349. assertex(strcmp(tags.item(2), "two, seven, eight, and nine o'clock")==0);
  1350. {
  1351. Owned<ICronTable::Transaction> frame(crontab->getTransactionFrame());
  1352. frame->remove("every minute");
  1353. //rolls back
  1354. }
  1355. in.set(2004, 12, 6, 7, 59, 0);
  1356. key.set(2004, 12, 6, 8, 0, 0);
  1357. ret = crontab->next(in, out, tags);
  1358. assertex(out == key);
  1359. assertex(ret==3);
  1360. assertex(strcmp(tags.item(0), "every minute")==0);
  1361. assertex(strcmp(tags.item(1), "every even minute")==0);
  1362. assertex(strcmp(tags.item(2), "two, seven, eight, and nine o'clock")==0);
  1363. {
  1364. Owned<ICronTable::Transaction> frame(crontab->getTransactionFrame());
  1365. frame->remove("every minute");
  1366. frame->commit();
  1367. }
  1368. in.set(2004, 12, 6, 7, 59, 0);
  1369. key.set(2004, 12, 6, 8, 0, 0);
  1370. ret = crontab->next(in, out, tags);
  1371. assertex(out == key);
  1372. assertex(ret==2);
  1373. assertex(strcmp(tags.item(0), "every even minute")==0);
  1374. assertex(strcmp(tags.item(1), "two, seven, eight, and nine o'clock")==0);
  1375. }
  1376. #endif
  1377. IJlibDateTime * createDateTimeFromLocal(time_t lt)
  1378. {
  1379. CScmDateTime * dt = new CScmDateTime();
  1380. dt->setSimpleLocal(lt);
  1381. return dt;
  1382. }
  1383. time_t createLocalFromDateTime(IJlibDateTime const * dt)
  1384. {
  1385. unsigned year;
  1386. unsigned month;
  1387. unsigned mday;
  1388. unsigned hour;
  1389. unsigned min;
  1390. unsigned sec;
  1391. unsigned nanosec;
  1392. dt->getLocalDate(year, month, mday);
  1393. dt->getLocalTime(hour, min, sec, nanosec);
  1394. tm ts;
  1395. ts.tm_year = year - 1900;
  1396. ts.tm_mon = month - 1;
  1397. ts.tm_mday = mday;
  1398. ts.tm_hour = hour;
  1399. ts.tm_min = min;
  1400. ts.tm_sec = sec;
  1401. ts.tm_isdst = -1; // leave determination of DST to RTL - hope this is ok
  1402. return mktime(&ts);
  1403. }
  1404. void timetToIDateTime(CDateTime * target, time_t time)
  1405. {
  1406. if (target)
  1407. {
  1408. struct tm tm_r;
  1409. struct tm * gmt = gmtime_r(&time, &tm_r);
  1410. target->setDate(gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday);
  1411. target->setTime(gmt->tm_hour, gmt->tm_min, gmt->tm_sec, 0);
  1412. }
  1413. }
  1414. time_t timetFromIDateTime(const CDateTime * source)
  1415. {
  1416. if (source == NULL)
  1417. return (time_t) 0;
  1418. unsigned bluff;
  1419. struct tm ttm;
  1420. // better fix: change the signature to unsigned's ??
  1421. source->getDate((unsigned &)ttm.tm_year, (unsigned &)ttm.tm_mon, (unsigned &)ttm.tm_mday);
  1422. source->getTime((unsigned &)ttm.tm_hour, (unsigned &)ttm.tm_min, (unsigned &)ttm.tm_sec, bluff);
  1423. ttm.tm_isdst = -1;
  1424. if(ttm.tm_year >= 1900)
  1425. ttm.tm_year -= 1900;
  1426. ttm.tm_mon -= 1;
  1427. time_t time = timegm(&ttm);
  1428. if (time == (time_t)-1)
  1429. time = 0;
  1430. return time;
  1431. }