timelib.cpp 29 KB

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