jtime.cpp 42 KB

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