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