timelib.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  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 <time.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <assert.h>
  19. #include <eclrtl.hpp>
  20. #ifdef _WIN32
  21. #include <sys/timeb.h>
  22. #endif
  23. #include "timelib.hpp"
  24. static const char * compatibleVersions[] = {
  25. NULL };
  26. #define TIMELIB_VERSION "TIMELIB 1.0.0"
  27. static const char * EclDefinition =
  28. "EXPORT TMPartsRec := RECORD \n"
  29. " INTEGER4 sec; \n"
  30. " INTEGER4 min; \n"
  31. " INTEGER4 hour; \n"
  32. " INTEGER4 mday; \n"
  33. " INTEGER4 mon; \n"
  34. " INTEGER4 year; \n"
  35. " INTEGER4 wday; \n"
  36. "END;"
  37. "EXPORT TMDateRangeRec := RECORD \n"
  38. " UNSIGNED4 startDate; \n"
  39. " UNSIGNED4 endDate; \n"
  40. "END;"
  41. "EXPORT TimeLib := SERVICE : fold\n"
  42. " INTEGER8 SecondsFromParts(INTEGER2 year, UNSIGNED1 month, UNSIGNED1 day, UNSIGNED1 hour, UNSIGNED1 minute, UNSIGNED1 second, BOOLEAN is_local_time) : c,pure,entrypoint='tlSecondsFromParts'; \n"
  43. " TRANSFORM(TMPartsRec) SecondsToParts(INTEGER8 seconds, BOOLEAN is_local_time = FALSE) : c,pure,entrypoint='tlSecondsToParts'; \n"
  44. " UNSIGNED2 GetDayOfYear(INTEGER2 year, UNSIGNED1 month, UNSIGNED1 day) : c,pure,entrypoint='tlGetDayOfYear'; \n"
  45. " UNSIGNED1 GetDayOfWeek(INTEGER2 year, UNSIGNED1 month, UNSIGNED1 day) : c,pure,entrypoint='tlGetDayOfWeek'; \n"
  46. " STRING DateToString(UNSIGNED4 date, CONST VARSTRING format) : c,pure,entrypoint='tlDateToString'; \n"
  47. " STRING TimeToString(UNSIGNED3 time, CONST VARSTRING format) : c,pure,entrypoint='tlTimeToString'; \n"
  48. " STRING SecondsToString(INTEGER8 seconds, CONST VARSTRING format) : c,pure,entrypoint='tlSecondsToString'; \n"
  49. " INTEGER8 StringToSeconds(CONST STRING src, CONST VARSTRING format, BOOLEAN is_local_time) : c,pure,entrypoint='tlStringToSeconds'; \n"
  50. " UNSIGNED4 AdjustDate(UNSIGNED4 date, INTEGER2 year_delta, INTEGER4 month_delta, INTEGER4 day_delta) : c,pure,entrypoint='tlAdjustDate'; \n"
  51. " UNSIGNED4 AdjustDateBySeconds(UNSIGNED4 date, INTEGER4 seconds_delta) : c,pure,entrypoint='tlAdjustDateBySeconds'; \n"
  52. " UNSIGNED4 AdjustTime(UNSIGNED3 time, INTEGER2 hour_delta, INTEGER4 minute_delta, INTEGER4 second_delta) : c,pure,entrypoint='tlAdjustTime'; \n"
  53. " UNSIGNED4 AdjustTimeBySeconds(UNSIGNED3 time, INTEGER4 seconds_delta) : c,pure,entrypoint='tlAdjustTimeBySeconds'; \n"
  54. " INTEGER4 AdjustSeconds(INTEGER8 seconds, INTEGER2 year_delta, INTEGER4 month_delta, INTEGER4 day_delta, INTEGER2 hour_delta, INTEGER4 minute_delta, INTEGER4 second_delta) : c,pure,entrypoint='tlAdjustSeconds'; \n"
  55. " UNSIGNED4 AdjustCalendar(UNSIGNED4 date, INTEGER2 year_delta, INTEGER4 month_delta, INTEGER4 day_delta) : c,pure,entrypoint='tlAdjustCalendar'; \n"
  56. " BOOLEAN IsLocalDaylightSavingsInEffect() : c,pure,entrypoint='tlIsLocalDaylightSavingsInEffect'; \n"
  57. " UNSIGNED4 GetLastDayOfMonth(UNSIGNED4 date) : c,pure,entrypoint='tlGetLastDayOfMonth'; \n"
  58. " TRANSFORM(TMDateRangeRec) DatesForWeek(UNSIGNED4 date) : c,pure,entrypoint='tlDatesForWeek'; \n"
  59. // NOTE - the next 5 are foldable but not pure, meaning it will only be folded if found in a #IF or similar
  60. // This is because you usually want them to be executed at runtime
  61. " INTEGER4 LocalTimeZoneOffset() : c,once,entrypoint='tlLocalTimeZoneOffset'; \n"
  62. " UNSIGNED4 CurrentDate(BOOLEAN in_local_time) : c,once,entrypoint='tlCurrentDate'; \n"
  63. " UNSIGNED4 CurrentTime(BOOLEAN in_local_time) : c,entrypoint='tlCurrentTime'; \n"
  64. " INTEGER8 CurrentSeconds(BOOLEAN in_local_time) : c,entrypoint='tlCurrentSeconds'; \n"
  65. " INTEGER8 CurrentTimestamp(BOOLEAN in_local_time) : c,entrypoint='tlCurrentTimestamp'; \n"
  66. "END;";
  67. TIMELIB_API bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb)
  68. {
  69. if (pb->size == sizeof(ECLPluginDefinitionBlockEx))
  70. {
  71. ECLPluginDefinitionBlockEx * pbx = (ECLPluginDefinitionBlockEx *) pb;
  72. pbx->compatibleVersions = compatibleVersions;
  73. }
  74. else if (pb->size != sizeof(ECLPluginDefinitionBlock))
  75. return false;
  76. pb->magicVersion = PLUGIN_VERSION;
  77. pb->version = TIMELIB_VERSION;
  78. pb->moduleName = "lib_timelib";
  79. pb->ECL = EclDefinition;
  80. pb->flags = PLUGIN_IMPLICIT_MODULE | PLUGIN_MULTIPLE_VERSIONS;
  81. pb->description = "TimeLib time manipulation library";
  82. return true;
  83. }
  84. IPluginContext * parentCtx = NULL;
  85. TIMELIB_API void setPluginContext(IPluginContext * _ctx) { parentCtx = _ctx; }
  86. //------------------------------------------------------------------------------
  87. #ifdef _WIN32
  88. const __int64 _onesec_in100ns = (__int64)10000000;
  89. static __int64 tlFileTimeToInt64(FILETIME f)
  90. {
  91. __int64 seconds;
  92. seconds = f.dwHighDateTime;
  93. seconds <<= 32;
  94. seconds |= f.dwLowDateTime;
  95. return seconds;
  96. }
  97. static FILETIME tlInt64ToFileTime(__int64 seconds)
  98. {
  99. FILETIME f;
  100. f.dwHighDateTime = (DWORD)((seconds >> 32) & 0x00000000FFFFFFFF);
  101. f.dwLowDateTime = (DWORD)(seconds & 0x00000000FFFFFFFF);
  102. return f;
  103. }
  104. static FILETIME tlFileTimeFromYear(WORD year)
  105. {
  106. SYSTEMTIME s;
  107. FILETIME f;
  108. memset(&s, 0, sizeof(s));
  109. s.wYear = year;
  110. s.wMonth = 1;
  111. s.wDayOfWeek = 1;
  112. s.wDay = 1;
  113. SystemTimeToFileTime(&s, &f);
  114. return f;
  115. }
  116. static unsigned int tlYearDayFromSystemTime(const SYSTEMTIME* s)
  117. {
  118. __int64 seconds;
  119. FILETIME f1;
  120. FILETIME f2;
  121. f1 = tlFileTimeFromYear(s->wYear);
  122. SystemTimeToFileTime(s, &f2);
  123. seconds = tlFileTimeToInt64(f2) - tlFileTimeToInt64(f1);
  124. return static_cast<unsigned int>((seconds / _onesec_in100ns) / (60 * 60 * 24));
  125. }
  126. static SYSTEMTIME tlTimeStructToSystemTime(const struct tm* timeInfoPtr)
  127. {
  128. SYSTEMTIME s;
  129. s.wYear = timeInfoPtr->tm_year + 1900;
  130. s.wMonth = timeInfoPtr->tm_mon + 1;
  131. s.wDayOfWeek = timeInfoPtr->tm_wday;
  132. s.wDay = timeInfoPtr->tm_mday;
  133. s.wHour = timeInfoPtr->tm_hour;
  134. s.wMinute = timeInfoPtr->tm_min;
  135. s.wSecond = timeInfoPtr->tm_sec;
  136. s.wMilliseconds = 0;
  137. return s;
  138. }
  139. static void tlSystemTimeToTimeStruct_r(const SYSTEMTIME* s, struct tm* timeInfoPtr)
  140. {
  141. memset(timeInfoPtr, 0, sizeof(struct tm));
  142. timeInfoPtr->tm_year = s->wYear - 1900;
  143. timeInfoPtr->tm_mon = s->wMonth - 1;
  144. timeInfoPtr->tm_wday = s->wDayOfWeek;
  145. timeInfoPtr->tm_mday = s->wDay;
  146. timeInfoPtr->tm_yday = tlYearDayFromSystemTime(s);
  147. timeInfoPtr->tm_hour = s->wHour;
  148. timeInfoPtr->tm_min = s->wMinute;
  149. timeInfoPtr->tm_sec = s->wSecond;
  150. timeInfoPtr->tm_isdst = 0;
  151. }
  152. static time_t tlFileTimeToSeconds(const FILETIME* f)
  153. {
  154. const __int64 offset = I64C(11644473600); // Number of seconds between 1601 and 1970 (Jan 1 of each)
  155. return static_cast<time_t>((tlFileTimeToInt64(*f) / _onesec_in100ns) - offset);
  156. }
  157. static FILETIME tlSecondsToFileTime(const time_t seconds)
  158. {
  159. FILETIME f1970 = tlFileTimeFromYear(1970);
  160. FILETIME f;
  161. __int64 time;
  162. time = (seconds * _onesec_in100ns) + tlFileTimeToInt64(f1970);
  163. f = tlInt64ToFileTime(time);
  164. return f;
  165. }
  166. static __int64 tlLocalTimeZoneDiffIn100nsIntervals()
  167. {
  168. SYSTEMTIME systemUTC;
  169. SYSTEMTIME systemLocal;
  170. FILETIME fileUTC;
  171. FILETIME fileLocal;
  172. GetSystemTime(&systemUTC);
  173. GetLocalTime(&systemLocal);
  174. SystemTimeToFileTime(&systemUTC, &fileUTC);
  175. SystemTimeToFileTime(&systemLocal, &fileLocal); // DST is accounted for
  176. return tlFileTimeToInt64(fileLocal) - tlFileTimeToInt64(fileUTC);
  177. }
  178. static void tlBoundaryMod(int* tensPtr, int* unitsPtr, int base)
  179. {
  180. if (*unitsPtr >= base)
  181. {
  182. *tensPtr += *unitsPtr / base;
  183. *unitsPtr %= base;
  184. }
  185. else if (*unitsPtr < 0)
  186. {
  187. --*tensPtr;
  188. *unitsPtr += base;
  189. if (*unitsPtr < 0)
  190. {
  191. *tensPtr -= 1 + (-*unitsPtr) / base;
  192. *unitsPtr = base - (-*unitsPtr) % base;
  193. if (*unitsPtr == base)
  194. {
  195. *tensPtr += 1;
  196. *unitsPtr = 0;
  197. }
  198. }
  199. }
  200. }
  201. static void tlNormalizeTimeStruct(struct tm* timeInfoPtr)
  202. {
  203. // Normalize incoming struct tm
  204. const int secondsPerMinute = 60;
  205. const int minutesPerHour = 60;
  206. const int hoursPerDay = 24;
  207. const int daysPerWeek = 7;
  208. const int daysPerNYear = 365;
  209. const int daysPerLYear = 366;
  210. const int yearLengths[2] = { daysPerNYear, daysPerLYear };
  211. const int secondsPerHour = secondsPerMinute * minutesPerHour;
  212. const long secondsPerDay = secondsPerHour * hoursPerDay;
  213. const int monthsPerYear = 12;
  214. const int yearBase = 1900;
  215. const int monthLengths[2][monthsPerYear] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
  216. int leapYearIndex = 0;
  217. tlBoundaryMod(&timeInfoPtr->tm_min, &timeInfoPtr->tm_sec, secondsPerMinute);
  218. tlBoundaryMod(&timeInfoPtr->tm_hour, &timeInfoPtr->tm_min, minutesPerHour);
  219. tlBoundaryMod(&timeInfoPtr->tm_mday, &timeInfoPtr->tm_hour, hoursPerDay);
  220. tlBoundaryMod(&timeInfoPtr->tm_year, &timeInfoPtr->tm_mon, monthsPerYear);
  221. leapYearIndex = ((((timeInfoPtr->tm_year + yearBase) % 4) == 0 && ((timeInfoPtr->tm_year + yearBase) % 100) != 0) || ((timeInfoPtr->tm_year + yearBase) % 400) == 0);
  222. while (timeInfoPtr->tm_mday <= 0)
  223. {
  224. --timeInfoPtr->tm_mon;
  225. if (timeInfoPtr->tm_mon < 0)
  226. {
  227. timeInfoPtr->tm_mon = 11;
  228. --timeInfoPtr->tm_year;
  229. leapYearIndex = ((((timeInfoPtr->tm_year + yearBase) % 4) == 0 && ((timeInfoPtr->tm_year + yearBase) % 100) != 0) || ((timeInfoPtr->tm_year + yearBase) % 400) == 0);
  230. }
  231. timeInfoPtr->tm_mday += monthLengths[leapYearIndex][timeInfoPtr->tm_mon];
  232. }
  233. while (timeInfoPtr->tm_mday > monthLengths[leapYearIndex][timeInfoPtr->tm_mon])
  234. {
  235. timeInfoPtr->tm_mday -= monthLengths[leapYearIndex][timeInfoPtr->tm_mon];
  236. ++timeInfoPtr->tm_mon;
  237. if (timeInfoPtr->tm_mon >= 12)
  238. {
  239. timeInfoPtr->tm_mon = 0;
  240. ++timeInfoPtr->tm_year;
  241. leapYearIndex = ((((timeInfoPtr->tm_year + yearBase) % 4) == 0 && ((timeInfoPtr->tm_year + yearBase) % 100) != 0) || ((timeInfoPtr->tm_year + yearBase) % 400) == 0);
  242. }
  243. }
  244. }
  245. //---------------------------
  246. static void tlWinLocalTime_r(const time_t* clock, struct tm* timeInfoPtr)
  247. {
  248. SYSTEMTIME s;
  249. FILETIME f;
  250. __int64 time;
  251. f = tlSecondsToFileTime(*clock);
  252. time = tlFileTimeToInt64(f) + tlLocalTimeZoneDiffIn100nsIntervals();
  253. f = tlInt64ToFileTime(time);
  254. FileTimeToSystemTime(&f, &s);
  255. tlSystemTimeToTimeStruct_r(&s, timeInfoPtr);
  256. }
  257. static void tlWinGMTime_r(const time_t* clock, struct tm* timeInfo)
  258. {
  259. FILETIME f;
  260. SYSTEMTIME s;
  261. f = tlSecondsToFileTime(*clock);
  262. FileTimeToSystemTime(&f, &s);
  263. tlSystemTimeToTimeStruct_r(&s, timeInfo);
  264. }
  265. static time_t tlWinMKTime(struct tm* timeInfoPtr)
  266. {
  267. SYSTEMTIME s;
  268. FILETIME f;
  269. time_t diff;
  270. // Windows apparently doesn't normalize/fix bogus date values before
  271. // doing conversions, so we need to normalize them first
  272. tlNormalizeTimeStruct(timeInfoPtr);
  273. s = tlTimeStructToSystemTime(timeInfoPtr);
  274. SystemTimeToFileTime(&s, &f);
  275. // Reset day of week
  276. FileTimeToSystemTime(&f, &s);
  277. timeInfoPtr->tm_wday = s.wDayOfWeek;
  278. // The above assumes UTC but Linux's mktime() assumes a local
  279. // time zone, so we need to offset the result into the local time zone
  280. diff = tlLocalTimeZoneDiffIn100nsIntervals() / _onesec_in100ns;
  281. return tlFileTimeToSeconds(&f) - diff;
  282. }
  283. #endif
  284. //------------------------------------------------------------------------------
  285. void tlLocalTime_r(const time_t* clock, struct tm* timeInfoPtr)
  286. {
  287. #ifdef _WIN32
  288. tlWinLocalTime_r(clock, timeInfoPtr);
  289. #else
  290. localtime_r(clock, timeInfoPtr);
  291. #endif
  292. }
  293. void tlGMTime_r(const time_t* clock, struct tm* timeInfoPtr)
  294. {
  295. #ifdef _WIN32
  296. tlWinGMTime_r(clock, timeInfoPtr);
  297. #else
  298. gmtime_r(clock, timeInfoPtr);
  299. #endif
  300. }
  301. time_t tlMKTime(struct tm* timeInfoPtr, bool inLocalTimeZone)
  302. {
  303. time_t the_time = 0;
  304. #ifdef _WIN32
  305. the_time = tlWinMKTime(timeInfoPtr);
  306. if (!inLocalTimeZone)
  307. {
  308. // Adjust for time zone and DST offset
  309. the_time += (tlLocalTimeZoneDiffIn100nsIntervals() / _onesec_in100ns);
  310. }
  311. #else
  312. // Get the initial time components; note that mktime assumes local time
  313. the_time = mktime(timeInfoPtr);
  314. if (!inLocalTimeZone)
  315. {
  316. // Adjust for time zone offset
  317. the_time += timeInfoPtr->tm_gmtoff;
  318. }
  319. #endif
  320. return the_time;
  321. }
  322. //------------------------------------------------------------------------------
  323. void tlMakeTimeStructFromSeconds(time_t seconds, struct tm* timeInfo, bool inLocalTimeZone)
  324. {
  325. if (inLocalTimeZone)
  326. {
  327. tlLocalTime_r(&seconds, timeInfo);
  328. }
  329. else
  330. {
  331. tlGMTime_r(&seconds, timeInfo);
  332. }
  333. }
  334. void tlInsertDateIntoTimeStruct(struct tm* timeInfo, unsigned int date)
  335. {
  336. unsigned int year = date / 10000;
  337. unsigned int month = (date - (year * 10000)) / 100;
  338. unsigned int day = date - (year * 10000) - (month * 100);
  339. timeInfo->tm_year = year - 1900;
  340. timeInfo->tm_mon = month - 1;
  341. timeInfo->tm_mday = day;
  342. }
  343. unsigned int tlExtractDateFromTimeStruct(const struct tm* timeInfo)
  344. {
  345. unsigned int result = 0;
  346. result = (timeInfo->tm_year + 1900) * 10000;
  347. result += (timeInfo->tm_mon + 1) * 100;
  348. result += timeInfo->tm_mday;
  349. return result;
  350. }
  351. void tlInsertTimeIntoTimeStruct(struct tm* timeInfo, unsigned int time)
  352. {
  353. unsigned int hour = time / 10000;
  354. unsigned int minute = (time - (hour * 10000)) / 100;
  355. unsigned int second = time - (hour * 10000) - (minute * 100);
  356. timeInfo->tm_hour = hour;
  357. timeInfo->tm_min = minute;
  358. timeInfo->tm_sec = second;
  359. }
  360. unsigned int tlExtractTimeFromTimeStruct(const struct tm* timeInfo)
  361. {
  362. unsigned int result = 0;
  363. result = timeInfo->tm_hour * 10000;
  364. result += timeInfo->tm_min * 100;
  365. result += timeInfo->tm_sec;
  366. return result;
  367. }
  368. //------------------------------------------------------------------------------
  369. TIMELIB_API __int64 TIMELIB_CALL tlSecondsFromParts(int year, unsigned int month, unsigned int day, unsigned int hour, unsigned int minute, unsigned int second, bool is_local_time)
  370. {
  371. struct tm timeInfo;
  372. time_t the_time = 0;
  373. memset(&timeInfo, 0, sizeof(timeInfo));
  374. // Push each time part value into the tm struct
  375. timeInfo.tm_sec = second;
  376. timeInfo.tm_min = minute;
  377. timeInfo.tm_hour = hour;
  378. timeInfo.tm_mday = day;
  379. timeInfo.tm_mon = month - 1;
  380. timeInfo.tm_year = year - 1900;
  381. timeInfo.tm_isdst = -1;
  382. the_time = tlMKTime(&timeInfo, is_local_time);
  383. return static_cast<__int64>(the_time);
  384. }
  385. //------------------------------------------------------------------------------
  386. TIMELIB_API size32_t TIMELIB_CALL tlSecondsToParts(ARowBuilder& __self, __int64 seconds, bool is_local_time)
  387. {
  388. struct tm timeInfo;
  389. struct TMParts
  390. {
  391. __int32 sec;
  392. __int32 min;
  393. __int32 hour;
  394. __int32 mday;
  395. __int32 mon;
  396. __int32 year;
  397. __int32 wday;
  398. };
  399. tlMakeTimeStructFromSeconds(seconds, &timeInfo, is_local_time);
  400. TMParts* result = reinterpret_cast<TMParts*>(__self.getSelf());
  401. result->sec = timeInfo.tm_sec;
  402. result->min = timeInfo.tm_min;
  403. result->hour = timeInfo.tm_hour;
  404. result->mday = timeInfo.tm_mday;
  405. result->mon = timeInfo.tm_mon;
  406. result->year = timeInfo.tm_year;
  407. result->wday = timeInfo.tm_wday;
  408. return static_cast<size32_t>(sizeof(TMParts));
  409. }
  410. //------------------------------------------------------------------------------
  411. TIMELIB_API unsigned int TIMELIB_CALL tlGetDayOfYear(short year, unsigned short month, unsigned short day)
  412. {
  413. unsigned int dayOfYear = 0;
  414. #ifdef _WIN32
  415. SYSTEMTIME s;
  416. memset(&s, 0, sizeof(s));
  417. s.wYear = year;
  418. s.wMonth = month;
  419. s.wDay = day;
  420. dayOfYear = tlYearDayFromSystemTime(&s);
  421. #else
  422. struct tm timeInfo;
  423. memset(&timeInfo, 0, sizeof(timeInfo));
  424. // Push each time part value into the tm struct
  425. timeInfo.tm_mday = day;
  426. timeInfo.tm_mon = month - 1;
  427. timeInfo.tm_year = year - 1900;
  428. timeInfo.tm_isdst = -1;
  429. tlMKTime(&timeInfo);
  430. dayOfYear = timeInfo.tm_yday;
  431. #endif
  432. return dayOfYear;
  433. }
  434. //------------------------------------------------------------------------------
  435. TIMELIB_API unsigned int TIMELIB_CALL tlGetDayOfWeek(short year, unsigned short month, unsigned short day)
  436. {
  437. struct tm timeInfo;
  438. memset(&timeInfo, 0, sizeof(timeInfo));
  439. // Push each time part value into the tm struct
  440. timeInfo.tm_mday = day;
  441. timeInfo.tm_mon = month - 1;
  442. timeInfo.tm_year = year - 1900;
  443. timeInfo.tm_isdst = -1;
  444. tlMKTime(&timeInfo);
  445. return timeInfo.tm_wday;
  446. }
  447. //------------------------------------------------------------------------------
  448. TIMELIB_API void TIMELIB_CALL tlDateToString(size32_t &__lenResult, char* &__result, unsigned int date, const char* format)
  449. {
  450. __result = NULL; // Return blank string on error
  451. __lenResult = 0;
  452. // date is expected to be in form year*10000 + month * 100 + day
  453. struct tm timeInfo;
  454. const size_t kBufferSize = 256;
  455. char buffer[kBufferSize];
  456. memset(&timeInfo, 0, sizeof(timeInfo));
  457. tlInsertDateIntoTimeStruct(&timeInfo, date);
  458. timeInfo.tm_isdst = -1;
  459. tlMKTime(&timeInfo);
  460. #if defined(__clang__) || defined(__GNUC__)
  461. #pragma GCC diagnostic push
  462. #pragma GCC diagnostic ignored "-Wformat-nonliteral"
  463. #endif
  464. __lenResult = strftime(buffer, kBufferSize, format, &timeInfo);
  465. #if defined(__clang__) || defined(__GNUC__)
  466. #pragma GCC diagnostic pop
  467. #endif
  468. if (__lenResult > 0)
  469. {
  470. __result = reinterpret_cast<char*>(CTXMALLOC(parentCtx, __lenResult));
  471. memcpy(__result, buffer, __lenResult);
  472. }
  473. }
  474. //------------------------------------------------------------------------------
  475. TIMELIB_API void TIMELIB_CALL tlTimeToString(size32_t &__lenResult, char* &__result, unsigned int time, const char* format)
  476. {
  477. struct tm timeInfo;
  478. const size_t kBufferSize = 256;
  479. char buffer[kBufferSize];
  480. memset(&timeInfo, 0, sizeof(timeInfo));
  481. tlInsertTimeIntoTimeStruct(&timeInfo, time);
  482. timeInfo.tm_isdst = -1;
  483. tlMKTime(&timeInfo);
  484. #if defined(__clang__) || defined(__GNUC__)
  485. #pragma GCC diagnostic push
  486. #pragma GCC diagnostic ignored "-Wformat-nonliteral"
  487. #endif
  488. __lenResult = strftime(buffer, kBufferSize, format, &timeInfo);
  489. #if defined(__clang__) || defined(__GNUC__)
  490. #pragma GCC diagnostic pop
  491. #endif
  492. __result = NULL;
  493. if (__lenResult > 0)
  494. {
  495. __result = reinterpret_cast<char*>(rtlMalloc(__lenResult));
  496. memcpy(__result, buffer, __lenResult);
  497. }
  498. }
  499. //------------------------------------------------------------------------------
  500. TIMELIB_API void TIMELIB_CALL tlSecondsToString(size32_t &__lenResult, char* &__result, __int64 seconds, const char* format)
  501. {
  502. struct tm timeInfo;
  503. time_t theTime = seconds;
  504. const size_t kBufferSize = 256;
  505. char buffer[kBufferSize];
  506. memset(buffer, 0, kBufferSize);
  507. tlGMTime_r(&theTime, &timeInfo);
  508. #if defined(__clang__) || defined(__GNUC__)
  509. #pragma GCC diagnostic push
  510. #pragma GCC diagnostic ignored "-Wformat-nonliteral"
  511. #endif
  512. __lenResult = strftime(buffer, kBufferSize, format, &timeInfo);
  513. #if defined(__clang__) || defined(__GNUC__)
  514. #pragma GCC diagnostic pop
  515. #endif
  516. __result = NULL;
  517. if (__lenResult > 0)
  518. {
  519. __result = reinterpret_cast<char*>(rtlMalloc(__lenResult));
  520. memcpy(__result, buffer, __lenResult);
  521. }
  522. }
  523. //------------------------------------------------------------------------------
  524. TIMELIB_API __int64 TIMELIB_CALL tlStringToSeconds(size32_t lenS, const char* s, const char* fmtin, bool is_local_time)
  525. {
  526. struct tm timeInfo;
  527. memset(&timeInfo, 0, sizeof(timeInfo));
  528. timeInfo.tm_isdst = -1;
  529. if (simple_strptime(lenS, s, fmtin, &timeInfo))
  530. {
  531. return static_cast<__int64>(tlMKTime(&timeInfo, is_local_time));
  532. }
  533. return 0;
  534. }
  535. //------------------------------------------------------------------------------
  536. TIMELIB_API unsigned int TIMELIB_CALL tlAdjustDate(unsigned int date, short year_delta, int month_delta, int day_delta)
  537. {
  538. struct tm timeInfo;
  539. unsigned int result = 0;
  540. memset(&timeInfo, 0, sizeof(timeInfo));
  541. tlInsertDateIntoTimeStruct(&timeInfo, date);
  542. timeInfo.tm_year += year_delta;
  543. timeInfo.tm_mon += month_delta;
  544. timeInfo.tm_mday += day_delta;
  545. timeInfo.tm_isdst = -1;
  546. tlMKTime(&timeInfo);
  547. result = tlExtractDateFromTimeStruct(&timeInfo);
  548. return result;
  549. }
  550. //------------------------------------------------------------------------------
  551. TIMELIB_API unsigned int TIMELIB_CALL tlAdjustDateBySeconds(unsigned int date, int seconds_delta)
  552. {
  553. struct tm timeInfo;
  554. unsigned int result = 0;
  555. memset(&timeInfo, 0, sizeof(timeInfo));
  556. tlInsertDateIntoTimeStruct(&timeInfo, date);
  557. timeInfo.tm_isdst = -1;
  558. timeInfo.tm_sec = seconds_delta;
  559. tlMKTime(&timeInfo);
  560. result = tlExtractDateFromTimeStruct(&timeInfo);
  561. return result;
  562. }
  563. //------------------------------------------------------------------------------
  564. TIMELIB_API unsigned int TIMELIB_CALL tlAdjustTime(unsigned int time, short hour_delta, int minute_delta, int second_delta)
  565. {
  566. struct tm timeInfo;
  567. unsigned int result = 0;
  568. memset(&timeInfo, 0, sizeof(timeInfo));
  569. #ifdef __APPLE__
  570. timeInfo.tm_year = 2;
  571. #endif
  572. tlInsertTimeIntoTimeStruct(&timeInfo, time);
  573. timeInfo.tm_isdst = -1;
  574. timeInfo.tm_hour += hour_delta;
  575. timeInfo.tm_min += minute_delta;
  576. timeInfo.tm_sec += second_delta;
  577. tlMKTime(&timeInfo);
  578. result = tlExtractTimeFromTimeStruct(&timeInfo);
  579. return result;
  580. }
  581. //------------------------------------------------------------------------------
  582. TIMELIB_API unsigned int TIMELIB_CALL tlAdjustTimeBySeconds(unsigned int time, int seconds_delta)
  583. {
  584. struct tm timeInfo;
  585. unsigned int result = 0;
  586. memset(&timeInfo, 0, sizeof(timeInfo));
  587. #ifdef __APPLE__
  588. timeInfo.tm_year = 2;
  589. #endif
  590. tlInsertTimeIntoTimeStruct(&timeInfo, time);
  591. timeInfo.tm_isdst = -1;
  592. timeInfo.tm_sec += seconds_delta;
  593. tlMKTime(&timeInfo);
  594. result = tlExtractTimeFromTimeStruct(&timeInfo);
  595. return result;
  596. }
  597. //------------------------------------------------------------------------------
  598. TIMELIB_API __int64 TIMELIB_CALL tlAdjustSeconds(__int64 seconds, short year_delta, int month_delta, int day_delta, short hour_delta, int minute_delta, int second_delta)
  599. {
  600. struct tm timeInfo;
  601. time_t theTime = seconds;
  602. time_t result = 0;
  603. tlLocalTime_r(&theTime, &timeInfo);
  604. timeInfo.tm_year += year_delta;
  605. timeInfo.tm_mon += month_delta;
  606. timeInfo.tm_mday += day_delta;
  607. timeInfo.tm_hour += hour_delta;
  608. timeInfo.tm_min += minute_delta;
  609. timeInfo.tm_sec += second_delta;
  610. result = tlMKTime(&timeInfo);
  611. return static_cast<__int64>(result);
  612. }
  613. //------------------------------------------------------------------------------
  614. TIMELIB_API unsigned int TIMELIB_CALL tlAdjustCalendar(unsigned int date, short year_delta, int month_delta, int day_delta)
  615. {
  616. struct tm timeInfo;
  617. unsigned int year = date / 10000;
  618. unsigned int month = (date - (year * 10000)) / 100;
  619. unsigned int day = date - (year * 10000) - (month * 100);
  620. int expectedMonthVal = month - 1;
  621. time_t seconds;
  622. unsigned int result = 0;
  623. // Normalize the expected month value
  624. if (month_delta > 0)
  625. {
  626. expectedMonthVal = (expectedMonthVal + month_delta) % 12;
  627. }
  628. else if (month_delta < 0)
  629. {
  630. expectedMonthVal = expectedMonthVal - ((-1 * month_delta) % 12);
  631. if (expectedMonthVal < 0)
  632. {
  633. expectedMonthVal += 12;
  634. }
  635. }
  636. memset(&timeInfo, 0, sizeof(timeInfo));
  637. timeInfo.tm_year = year - 1900;
  638. timeInfo.tm_mon = month - 1;
  639. timeInfo.tm_mday = day;
  640. timeInfo.tm_year += year_delta;
  641. timeInfo.tm_mon += month_delta;
  642. timeInfo.tm_isdst = -1;
  643. seconds = tlMKTime(&timeInfo);
  644. if (timeInfo.tm_mon != expectedMonthVal)
  645. {
  646. // If the returned month doesn't match the expected month, we need to
  647. // go back to the last day of the previous month
  648. timeInfo.tm_mday = 0;
  649. timeInfo.tm_isdst = -1; // in case DST is different
  650. tlMKTime(&timeInfo);
  651. }
  652. if (day_delta != 0)
  653. {
  654. // Now apply the day delta
  655. timeInfo.tm_mday += day_delta;
  656. timeInfo.tm_isdst = -1; // in case DST is different
  657. tlMKTime(&timeInfo);
  658. }
  659. result = tlExtractDateFromTimeStruct(&timeInfo);
  660. return result;
  661. }
  662. //------------------------------------------------------------------------------
  663. TIMELIB_API bool TIMELIB_CALL tlIsLocalDaylightSavingsInEffect()
  664. {
  665. struct tm timeInfo;
  666. time_t theTime = time(NULL);
  667. tlLocalTime_r(&theTime, &timeInfo);
  668. return (timeInfo.tm_isdst == 1);
  669. }
  670. //------------------------------------------------------------------------------
  671. TIMELIB_API int TIMELIB_CALL tlLocalTimeZoneOffset()
  672. {
  673. int offset = 0;
  674. #ifdef _WIN32
  675. offset = static_cast<int>(tlLocalTimeZoneDiffIn100nsIntervals() / _onesec_in100ns);
  676. #else
  677. struct tm timeInfo;
  678. time_t theTime = time(NULL);
  679. tlLocalTime_r(&theTime, &timeInfo);
  680. offset = timeInfo.tm_gmtoff;
  681. #endif
  682. return offset;
  683. }
  684. //------------------------------------------------------------------------------
  685. TIMELIB_API unsigned int TIMELIB_CALL tlCurrentDate(bool in_local_time)
  686. {
  687. struct tm timeInfo;
  688. time_t theTime = time(NULL);
  689. unsigned int result = 0;
  690. // Create time parts differently depending on whether you need
  691. // UTC or local time
  692. if (in_local_time)
  693. {
  694. tlLocalTime_r(&theTime, &timeInfo);
  695. }
  696. else
  697. {
  698. tlGMTime_r(&theTime, &timeInfo);
  699. }
  700. result = tlExtractDateFromTimeStruct(&timeInfo);
  701. return result;
  702. }
  703. //------------------------------------------------------------------------------
  704. TIMELIB_API unsigned int TIMELIB_CALL tlCurrentTime(bool in_local_time)
  705. {
  706. struct tm timeInfo;
  707. time_t theTime = time(NULL);
  708. unsigned int result = 0;
  709. // Create time parts differently depending on whether you need
  710. // UTC or local time
  711. if (in_local_time)
  712. {
  713. tlLocalTime_r(&theTime, &timeInfo);
  714. }
  715. else
  716. {
  717. tlGMTime_r(&theTime, &timeInfo);
  718. }
  719. result = tlExtractTimeFromTimeStruct(&timeInfo);
  720. return result;
  721. }
  722. //------------------------------------------------------------------------------
  723. TIMELIB_API __int64 TIMELIB_CALL tlCurrentSeconds(bool in_local_time)
  724. {
  725. time_t result = time(NULL);
  726. if (in_local_time)
  727. {
  728. result += tlLocalTimeZoneOffset();
  729. }
  730. return static_cast<__int64>(result);
  731. }
  732. //------------------------------------------------------------------------------
  733. TIMELIB_API __int64 TIMELIB_CALL tlCurrentTimestamp(bool in_local_time)
  734. {
  735. __int64 result = 0;
  736. #ifdef _WIN32
  737. struct _timeb now;
  738. _ftime_s(&now);
  739. result = (now.time * I64C(1000000)) + (now.millitm * 1000);
  740. #else
  741. struct timeval tv;
  742. if (gettimeofday(&tv, NULL) == 0)
  743. {
  744. result = (tv.tv_sec * I64C(1000000)) + tv.tv_usec;
  745. }
  746. #endif
  747. if (in_local_time)
  748. {
  749. result += (static_cast<__int64>(tlLocalTimeZoneOffset()) * I64C(1000000));
  750. }
  751. return result;
  752. }
  753. //------------------------------------------------------------------------------
  754. TIMELIB_API unsigned int TIMELIB_CALL tlGetLastDayOfMonth(unsigned int date)
  755. {
  756. struct tm timeInfo;
  757. unsigned int result = 0;
  758. memset(&timeInfo, 0, sizeof(timeInfo));
  759. tlInsertDateIntoTimeStruct(&timeInfo, date);
  760. timeInfo.tm_isdst = -1;
  761. // Call mktime once to fix up any bogus data
  762. tlMKTime(&timeInfo);
  763. // Adjust and call again
  764. timeInfo.tm_mon += 1;
  765. timeInfo.tm_mday = 0;
  766. timeInfo.tm_isdst = -1; // in case DST is different
  767. tlMKTime(&timeInfo);
  768. result = tlExtractDateFromTimeStruct(&timeInfo);
  769. return result;
  770. }
  771. //------------------------------------------------------------------------------
  772. TIMELIB_API size32_t TIMELIB_CALL tlDatesForWeek(ARowBuilder& __self, unsigned int date)
  773. {
  774. struct tm timeInfo;
  775. struct TMDateRange
  776. {
  777. unsigned int startDate;
  778. unsigned int endDate;
  779. };
  780. TMDateRange* result = reinterpret_cast<TMDateRange*>(__self.getSelf());
  781. memset(&timeInfo, 0, sizeof(timeInfo));
  782. tlInsertDateIntoTimeStruct(&timeInfo, date);
  783. timeInfo.tm_isdst = -1;
  784. // Call mktime once to fix up any bogus data
  785. tlMKTime(&timeInfo);
  786. // Adjust and call again
  787. timeInfo.tm_mday -= timeInfo.tm_wday;
  788. timeInfo.tm_isdst = -1; // in case DST is different
  789. tlMKTime(&timeInfo);
  790. result->startDate = tlExtractDateFromTimeStruct(&timeInfo);
  791. // Adjust to the beginning of the week
  792. timeInfo.tm_mday += 6;
  793. timeInfo.tm_isdst = -1; // in case DST is different
  794. tlMKTime(&timeInfo);
  795. result->endDate = tlExtractDateFromTimeStruct(&timeInfo);
  796. return static_cast<size32_t>(sizeof(TMDateRange));
  797. }