jtime.cpp 42 KB

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