Date.ecl 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. /*##############################################################################
  2. ## HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®. All rights reserved.
  3. ############################################################################## */
  4. /* The functions defined in this module are provisional, and subject to change */
  5. IMPORT lib_stringlib.StringLib;
  6. IMPORT lib_timelib.TimeLib;
  7. EXPORT Date := MODULE
  8. // A record structure with the different date elements separated out.
  9. EXPORT Date_rec := RECORD
  10. INTEGER2 year;
  11. UNSIGNED1 month;
  12. UNSIGNED1 day;
  13. END;
  14. // An unsigned number holding a date in the decimal form YYYYMMDD.
  15. // This type doesn't support dates before 1AD.
  16. EXPORT Date_t := UNSIGNED4;
  17. // A number of elapsed days. Origin depends on the function called.
  18. EXPORT Days_t := INTEGER4;
  19. // A record structure with the different time elements separated out.
  20. EXPORT Time_rec := RECORD
  21. UNSIGNED1 hour;
  22. UNSIGNED1 minute;
  23. UNSIGNED1 second;
  24. END;
  25. // An unsigned number holding a time of day in the decimal form HHMMDD.
  26. EXPORT Time_t := UNSIGNED3;
  27. // A signed number holding a number of seconds. Can be used to represent either
  28. // a duration or the number of seconds since epoch (Jan 1, 1970).
  29. EXPORT Seconds_t := INTEGER8;
  30. // A record structure with the different date and time elements separated out.
  31. EXPORT DateTime_rec := RECORD
  32. Date_rec;
  33. Time_Rec;
  34. END;
  35. // A signed number holding a number of microseconds. Can be used to represent
  36. // either a duration or the number of microseconds since epoch (Jan 1, 1970).
  37. EXPORT Timestamp_t := INTEGER8;
  38. /**
  39. * Extracts the year from a date type.
  40. *
  41. * @param date The date.
  42. * @return An integer representing the year.
  43. */
  44. EXPORT INTEGER2 Year(Date_t date) := date DIV 10000;
  45. /**
  46. * Extracts the month from a date type.
  47. *
  48. * @param date The date.
  49. * @return An integer representing the year.
  50. */
  51. EXPORT UNSIGNED1 Month(Date_t date) := (date DIV 100) % 100;
  52. /**
  53. * Extracts the day of the month from a date type.
  54. *
  55. * @param date The date.
  56. * @return An integer representing the year.
  57. */
  58. EXPORT UNSIGNED1 Day(Date_t date) := date % 100;
  59. /**
  60. * Extracts the hour from a time type.
  61. *
  62. * @param time The time.
  63. * @return An integer representing the hour.
  64. */
  65. EXPORT UNSIGNED1 Hour(Time_t time) := time DIV 10000;
  66. /**
  67. * Extracts the minutes from a time type.
  68. *
  69. * @param time The time.
  70. * @return An integer representing the minutes.
  71. */
  72. EXPORT UNSIGNED1 Minute(Time_t time) := (time DIV 100) % 100;
  73. /**
  74. * Extracts the seconds from a time type.
  75. *
  76. * @param time The time.
  77. * @return An integer representing the seconds.
  78. */
  79. EXPORT UNSIGNED1 Second(Time_t time) := time % 100;
  80. /**
  81. * Combines year, month day to create a date type.
  82. *
  83. * @param year The year (0-9999).
  84. * @param month The month (1-12).
  85. * @param day The day (1..daysInMonth).
  86. * @return A date created by combining the fields.
  87. */
  88. EXPORT Date_t DateFromParts(INTEGER2 year, UNSIGNED1 month, UNSIGNED1 day) := (year * 100 + month) * 100 + day;
  89. /**
  90. * Combines hour, minute second to create a time type.
  91. *
  92. * @param hour The hour (0-23).
  93. * @param minute The minute (0-59).
  94. * @param second The second (0-59).
  95. * @return A time created by combining the fields.
  96. */
  97. EXPORT Time_t TimeFromParts(UNSIGNED1 hour, UNSIGNED1 minute, UNSIGNED1 second) := (hour * 100 + minute) * 100 + second;
  98. /**
  99. * Combines date and time components to create a seconds type. The date must
  100. * be represented within the Gregorian calendar after the year 1600.
  101. *
  102. * @param year The year (1601-30827).
  103. * @param month The month (1-12).
  104. * @param day The day (1..daysInMonth).
  105. * @param hour The hour (0-23).
  106. * @param minute The minute (0-59).
  107. * @param second The second (0-59).
  108. * @param is_local_time TRUE if the datetime components are expressed
  109. * in local time rather than UTC, FALSE if the
  110. * components are expressed in UTC. Optional,
  111. * defaults to FALSE.
  112. * @return A Seconds_t value created by combining the fields.
  113. */
  114. EXPORT Seconds_t SecondsFromParts(INTEGER2 year,
  115. UNSIGNED1 month,
  116. UNSIGNED1 day,
  117. UNSIGNED1 hour,
  118. UNSIGNED1 minute,
  119. UNSIGNED1 second,
  120. BOOLEAN is_local_time = FALSE) :=
  121. TimeLib.SecondsFromParts(year, month, day, hour, minute, second, is_local_time);
  122. /**
  123. * Converts the number of seconds since epoch to a structure containing
  124. * date and time parts. The result must be representable within the
  125. * Gregorian calendar after the year 1600.
  126. *
  127. * @param seconds The number of seconds since epoch.
  128. * @return Module with exported attributes for year, month,
  129. * day, hour, minute, second, day_of_week, date
  130. * and time.
  131. */
  132. EXPORT SecondsToParts(Seconds_t seconds) := FUNCTION
  133. parts := ROW(TimeLib.SecondsToParts(seconds));
  134. result := MODULE
  135. EXPORT INTEGER2 year := parts.year + 1900;
  136. EXPORT UNSIGNED1 month := parts.mon + 1;
  137. EXPORT UNSIGNED1 day := parts.mday;
  138. EXPORT UNSIGNED1 hour := parts.hour;
  139. EXPORT UNSIGNED1 minute := parts.min;
  140. EXPORT UNSIGNED1 second := parts.sec;
  141. EXPORT UNSIGNED1 day_of_week := parts.wday + 1;
  142. EXPORT Date_t date := DateFromParts(year,month,day);
  143. EXPORT Time_t time := TimeFromParts(hour,minute,second);
  144. END;
  145. RETURN result;
  146. END;
  147. /**
  148. * Converts the number of microseconds since epoch to the number of seconds
  149. * since epoch.
  150. *
  151. * @param timestamp The number of microseconds since epoch.
  152. * @return The number of seconds since epoch.
  153. */
  154. EXPORT Seconds_t TimestampToSeconds(Timestamp_t timestamp) := timestamp DIV 1000000;
  155. /**
  156. * Tests whether the year is a leap year in the Gregorian calendar.
  157. *
  158. * @param year The year (0-9999).
  159. * @return True if the year is a leap year.
  160. */
  161. EXPORT BOOLEAN IsLeapYear(INTEGER2 year) := (year % 4 = 0) AND ((year % 100 != 0) OR (year % 400 = 0));
  162. /**
  163. * Tests whether a date is a leap year in the Gregorian calendar.
  164. *
  165. * @param date The date.
  166. * @return True if the year is a leap year.
  167. */
  168. EXPORT BOOLEAN IsDateLeapYear(Date_t date) := IsLeapYear(Year(date));
  169. SHARED YearDelta := +4800; // Offset the years by 4800 so dates up to -4713 work
  170. SHARED GregorianDateOrigin := -1753469; // 1 Jan 1AD = 1
  171. /**
  172. * Combines year, month, day in the Gregorian calendar to create the number
  173. * days since 31st December 1BC.
  174. *
  175. * @param year The year (-4713..9999).
  176. * @param month The month (1-12).
  177. * @param day The day (1..daysInMonth).
  178. * @return The number of elapsed days (1 Jan 1AD = 1)
  179. */
  180. EXPORT Days_t FromGregorianYMD(INTEGER2 year, UNSIGNED1 month, UNSIGNED1 day) := FUNCTION
  181. //See Frequently Asked Questions about Calendars by Claus Toendering
  182. a := (14 - month) DIV 12;
  183. y := year + YearDelta - a;
  184. m := month + 12*a - 3;
  185. jd := day + (153 * m + 2) DIV 5 + 365 * y + y DIV 4 - y DIV 100 + y DIV 400;
  186. RETURN jd + (GregorianDateOrigin - 1);
  187. END;
  188. /**
  189. * Converts the number days since 31st December 1BC to a date in the Gregorian calendar.
  190. *
  191. * @param days The number of elapsed days (1 Jan 1AD = 1)
  192. * @return Module containing Year, Month, Day in the Gregorian calendar
  193. */
  194. EXPORT ToGregorianYMD(Days_t days) := FUNCTION
  195. // See Fliegel and van Flandern (1968) and other quoted sources
  196. // (e.g., http://www.ortelius.de/kalender/calc_en.php)
  197. // Process as 4, 100 and 400 year cycles.
  198. daysIn4Years := 3*365+366;
  199. daysIn100Years := 25*daysIn4Years-1;
  200. daysIn400Years := 4*daysIn100Years+1;
  201. // Calculate days in each of the cycles.
  202. adjustedDays := days - GregorianDateOrigin;
  203. num400Years := adjustedDays div daysIn400Years;
  204. rem400Years := adjustedDays % daysIn400Years;
  205. num100Years := ((rem400Years div daysIn100Years + 1) * 3) DIV 4;
  206. rem100Years := rem400Years - num100Years * daysIn100Years;
  207. num4Years := rem100Years div daysIn4Years;
  208. rem4Years := rem100Years % daysIn4Years;
  209. years := ((rem4Years div 365 + 1) * 3) DIV 4;
  210. numdays := rem4Years - years * 365;
  211. //Now calculate the actual year, month day
  212. y := num400Years * 400 + num100Years * 100 + num4Years * 4 + years;
  213. m := (numdays * 5 + 308) div 153 - 2;
  214. d := numdays - (m + 4) * 153 div 5 + 122;
  215. result := MODULE
  216. EXPORT year := (y + (m + 2) div 12) - YearDelta;
  217. EXPORT month := (m + 2) % 12 + 1;
  218. EXPORT day := d + 1;
  219. END;
  220. RETURN result;
  221. END;
  222. /**
  223. * Converts a date in the Gregorian calendar to the number days since 31st December 1BC.
  224. *
  225. * @param date The date (using the Gregorian calendar)
  226. * @return The number of elapsed days (1 Jan 1AD = 1)
  227. */
  228. EXPORT Days_t FromGregorianDate(Date_t date) :=
  229. DEFINE FromGregorianYMD(Year(date), Month(date), Day(date));
  230. /**
  231. * Converts the number days since 31st December 1BC to a date in the Gregorian calendar.
  232. *
  233. * @param days The number of elapsed days (1 Jan 1AD = 1)
  234. * @return A Date_t in the Gregorian calendar
  235. */
  236. EXPORT Date_t ToGregorianDate(Days_t days) := DEFINE FUNCTION
  237. date := ToGregorianYMD(days);
  238. RETURN DateFromParts(date.year, date.month, date.day);
  239. END;
  240. /**
  241. * Returns a number representing the day of the year indicated by the given date.
  242. * The date must be in the Gregorian calendar after the year 1600.
  243. *
  244. * @param date A Date_t value.
  245. * @return A number (1-366) representing the number of days since
  246. * the beginning of the year.
  247. */
  248. EXPORT UNSIGNED2 DayOfYear(Date_t date) := FUNCTION
  249. theYear := Year(date);
  250. theMonth := Month(date);
  251. theDay := Day(date);
  252. dayNum := TimeLib.GetDayOfYear(theYear, theMonth, theDay) + 1;
  253. RETURN dayNum;
  254. END;
  255. /**
  256. * Returns a number representing the day of the week indicated by the given date.
  257. * The date must be in the Gregorian calendar after the year 1600.
  258. *
  259. * @param date A Date_t value.
  260. * @return A number 1-7 representing the day of the week, where 1 = Sunday.
  261. */
  262. EXPORT UNSIGNED1 DayOfWeek(Date_t date) := FUNCTION
  263. theYear := Year(date);
  264. theMonth := Month(date);
  265. theDay := Day(date);
  266. dayCode := TimeLib.GetDayOfWeek(theYear, theMonth, theDay) + 1;
  267. RETURN dayCode;
  268. END;
  269. /**
  270. * Tests whether the year is a leap year in the Julian calendar.
  271. *
  272. * @param year The year (0-9999).
  273. * @return True if the year is a leap year.
  274. */
  275. EXPORT BOOLEAN IsJulianLeapYear(INTEGER2 year) := (year % 4 = 0);
  276. SHARED JulianDateOrigin := -1753505; // 1 Jan 1AD = 1
  277. /**
  278. * Combines year, month, day in the Julian calendar to create the number
  279. * days since 31st December 1BC.
  280. *
  281. * @param year The year (-4800..9999).
  282. * @param month The month (1-12).
  283. * @param day The day (1..daysInMonth).
  284. * @return The number of elapsed days (1 Jan 1AD = 1)
  285. */
  286. EXPORT Days_t FromJulianYMD(INTEGER2 year, UNSIGNED1 month, UNSIGNED1 day) := FUNCTION
  287. //See Frequently Asked Questions about Calendars by Claus Toendering
  288. a := (14 - month) DIV 12;
  289. y := year + YearDelta - a;
  290. m := month + 12*a - 3;
  291. jd := day + (153 * m + 2) DIV 5 + 365 * y + y DIV 4;
  292. RETURN jd + (JulianDateOrigin-1);
  293. END;
  294. /**
  295. * Converts the number days since 31st December 1BC to a date in the Julian calendar.
  296. *
  297. * @param days The number of elapsed days (1 Jan 1AD = 1)
  298. * @return Module containing Year, Month, Day in the Julian calendar
  299. */
  300. EXPORT ToJulianYMD(Days_t days) := FUNCTION
  301. //See Frequently Asked Questions about Calendars by Claus Toendering
  302. daysIn4Years := 3*365+366;
  303. c := days - JulianDateOrigin;
  304. d := (4 * c + 3) DIV daysIn4Years;
  305. e := c - ((daysIn4Years * d) DIV 4);
  306. m := (5 * e + 2) DIV 153;
  307. result := MODULE
  308. EXPORT UNSIGNED1 day := e - ((153 * m + 2) DIV 5) + 1;
  309. EXPORT UNSIGNED1 month := m + 3 - 12 * (m DIV 10);
  310. EXPORT INTEGER2 year := d - YearDelta + (m DIV 10);
  311. END;
  312. RETURN result;
  313. END;
  314. /**
  315. * Converts a date in the Julian calendar to the number days since 31st December 1BC.
  316. *
  317. * @param date The date (using the Julian calendar)
  318. * @return The number of elapsed days (1 Jan 1AD = 1)
  319. */
  320. EXPORT Days_t FromJulianDate(Date_t date) := DEFINE FromJulianYMD(Year(date), Month(date), Day(date));
  321. /**
  322. * Converts the number days since 31st December 1BC to a date in the Julian calendar.
  323. *
  324. * @param days The number of elapsed days (1 Jan 1AD = 1)
  325. * @return A Date_t in the Julian calendar
  326. */
  327. EXPORT Date_t ToJulianDate(Days_t days) := DEFINE FUNCTION
  328. date := ToJulianYMD(days);
  329. RETURN DateFromParts(date.year, date.month, date.day);
  330. END;
  331. SHARED Date1900Delta := 693596; // 1 Jan 1900 = 0
  332. /**
  333. * Returns the number of days since 1st January 1900 (using the Gregorian Calendar)
  334. *
  335. * @param year The year (-4713..9999).
  336. * @param month The month (1-12).
  337. * @param day The day (1..daysInMonth).
  338. * @return The number of elapsed days since 1st January 1900
  339. */
  340. EXPORT Days_t DaysSince1900(INTEGER2 year, UNSIGNED1 month, UNSIGNED1 day) :=
  341. FromGregorianYMD(year, month, day) - Date1900Delta;
  342. /**
  343. * Returns the number of days since 1st January 1900 (using the Gregorian Calendar)
  344. *
  345. * @param date The date
  346. * @return The number of elapsed days since 1st January 1900
  347. */
  348. EXPORT Days_t ToDaysSince1900(Date_t date) := DaysSince1900(Year(date),Month(date),Day(date));
  349. /**
  350. * Converts the number days since 1st January 1900 to a date in the Julian calendar.
  351. *
  352. * @param days The number of elapsed days since 1st Jan 1900
  353. * @return A Date_t in the Julian calendar
  354. */
  355. EXPORT Date_t FromDaysSince1900(Days_t days) := ToGregorianDate(days + Date1900Delta);
  356. /**
  357. * Calculate the number of whole years between two dates.
  358. *
  359. * @param from The first date
  360. * @param to The last date
  361. * @return The number of years between them.
  362. */
  363. EXPORT INTEGER YearsBetween (Date_t from, Date_t to) := FUNCTION
  364. fromDate := MIN(from, to);
  365. toDate := MAX(from, to);
  366. years := Year(toDate) - Year(fromDate);
  367. adjustedYears := years - IF(Month(fromDate) > Month(toDate) OR (Month(fromDate) = Month(toDate) AND Day(fromDate) > Day(toDate)), 1, 0);
  368. RETURN adjustedYears * IF(from > to, -1, 1);
  369. END;
  370. /**
  371. * Calculate the number of whole months between two dates.
  372. *
  373. * @param from The first date
  374. * @param to The last date
  375. * @return The number of months between them.
  376. */
  377. EXPORT INTEGER MonthsBetween(Date_t from, Date_t to) := FUNCTION
  378. fromDate := MIN(from, to);
  379. toDate := MAX(from, to);
  380. years := Year(toDate) - Year(fromDate);
  381. months := Month(toDate) - Month(fromDate);
  382. result := years * 12 + months;
  383. adjustedResult := result - IF(Day(fromDate) > Day(toDate), 1, 0);
  384. RETURN adjustedResult * IF(from > to, -1, 1);
  385. END;
  386. /**
  387. * Calculate the number of days between two dates.
  388. *
  389. * @param from The first date
  390. * @param to The last date
  391. * @return The number of days between them.
  392. */
  393. EXPORT INTEGER DaysBetween(Date_t from, Date_t to) := FUNCTION
  394. fromDays := FromGregorianDate(from);
  395. toDays := FromGregorianDate(to);
  396. RETURN toDays - fromDays;
  397. END;
  398. /**
  399. * Combines the fields from a Date_rec to create a Date_t
  400. *
  401. * @param date The row containing the date.
  402. * @return A Date_t representing the combined values.
  403. */
  404. EXPORT Date_t DateFromDateRec(Date_rec date) := (date.year * 100 + date.month) * 100 + date.day;
  405. /**
  406. * Combines the fields from a Date_rec to create a Date_t
  407. *
  408. * @param date The row containing the date.
  409. * @return A Date_t representing the combined values.
  410. */
  411. EXPORT Date_t DateFromRec(Date_rec date) := DateFromDateRec(date) : DEPRECATED('Replaced with DateFromDateRec() function');
  412. /**
  413. * Combines the fields from a Time_rec to create a Time_t
  414. *
  415. * @param time The row containing the time.
  416. * @return A Time_t representing the combined values.
  417. */
  418. EXPORT Time_t TimeFromTimeRec(Time_rec time) := (time.hour * 100 + time.minute) * 100 + time.second;
  419. /**
  420. * Combines the date fields from a DateTime_rec to create a Date_t
  421. *
  422. * @param datetime The row containing the datetime.
  423. * @return A Date_t representing the combined values.
  424. */
  425. EXPORT Date_t DateFromDateTimeRec(DateTime_rec datetime) := (datetime.year * 100 + datetime.month) * 100 + datetime.day;
  426. /**
  427. * Combines the time fields from a DateTime_rec to create a Time_t
  428. *
  429. * @param datetime The row containing the datetime.
  430. * @return A Time_t representing the combined values.
  431. */
  432. EXPORT Time_t TimeFromDateTimeRec(DateTime_rec datetime) := (datetime.hour * 100 + datetime.minute) * 100 + datetime.second;
  433. /**
  434. * Combines the date and time fields from a DateTime_rec to create a Seconds_t
  435. *
  436. * @param datetime The row containing the datetime.
  437. * @param is_local_time TRUE if the datetime components are expressed in local
  438. * time rather than UTC, FALSE if the components are
  439. * expressed in UTC. Optional, defaults to FALSE.
  440. * @return A Seconds_t representing the combined values.
  441. */
  442. EXPORT Seconds_t SecondsFromDateTimeRec(DateTime_rec datetime, BOOLEAN is_local_time = FALSE) :=
  443. SecondsFromParts(datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second, is_local_time);
  444. /**
  445. * Converts a string to a Date_t using the relevant string format. The resulting
  446. * date must be representable within the Gregorian calendar after the year 1600.
  447. *
  448. * @param date_text The string to be converted.
  449. * @param format The format of the input string.
  450. * (See documentation for strftime)
  451. * @return The date that was matched in the string. Returns 0 if failed to match
  452. * or if the date components match but the result is an invalid date.
  453. *
  454. * Supported characters:
  455. %B Full month name
  456. %b or %h Abbreviated month name
  457. %d Day of month (two digits)
  458. %e Day of month (two digits, or a space followed by a single digit)
  459. %m Month (two digits)
  460. %t Whitespace
  461. %y year within century (00-99)
  462. %Y Full year (yyyy)
  463. %j Julian day (1-366)
  464. Common date formats
  465. American '%m/%d/%Y' mm/dd/yyyy
  466. Euro '%d/%m/%Y' dd/mm/yyyy
  467. Iso format '%Y-%m-%d' yyyy-mm-dd
  468. Iso basic 'Y%m%d' yyyymmdd
  469. '%d-%b-%Y' dd-mon-yyyy e.g., '21-Mar-1954'
  470. */
  471. EXPORT Date_t FromStringToDate(STRING date_text, VARSTRING format) :=
  472. StringLib.StringToDate(date_text, format);
  473. /**
  474. * Converts a string to a date using the relevant string format.
  475. *
  476. * @param date_text The string to be converted.
  477. * @param format The format of the input string.
  478. * (See documentation for strftime)
  479. * @return The date that was matched in the string.
  480. * Returns 0 if failed to match.
  481. */
  482. EXPORT Date_t FromString(STRING date_text, VARSTRING format) :=
  483. FromStringToDate(date_text, format) : DEPRECATED('Replaced with FromStringToDate() function');
  484. /**
  485. * Converts a string to a Time_t using the relevant string format.
  486. *
  487. * @param date_text The string to be converted.
  488. * @param format The format of the input string.
  489. * (See documentation for strftime)
  490. * @return The time that was matched in the string. Returns 0 if failed to match.
  491. *
  492. * Supported characters:
  493. %H Hour (two digits)
  494. %k (two digits, or a space followed by a single digit)
  495. %M Minute (two digits)
  496. %S Second (two digits)
  497. %t Whitespace
  498. */
  499. EXPORT Time_t FromStringToTime(STRING time_text, VARSTRING format) :=
  500. StringLib.StringToTimeOfDay(time_text, format);
  501. /**
  502. * Matches a string against a set of date string formats and returns a valid
  503. * Date_t object from the first format that successfully parses the string.
  504. *
  505. * @param date_text The string to be converted.
  506. * @param formats A set of formats to check against the string.
  507. * (See documentation for strftime)
  508. * @return The date that was matched in the string.
  509. * Returns 0 if failed to match.
  510. */
  511. EXPORT Date_t MatchDateString(STRING date_text, SET OF VARSTRING formats) :=
  512. StringLib.MatchDate(date_text, formats);
  513. /**
  514. * Matches a string against a set of time string formats and returns a valid
  515. * Time_t object from the first format that successfully parses the string.
  516. *
  517. * @param time_text The string to be converted.
  518. * @param formats A set of formats to check against the string.
  519. * (See documentation for strftime)
  520. * @return The time that was matched in the string.
  521. * Returns 0 if failed to match.
  522. */
  523. EXPORT Time_t MatchTimeString(STRING time_text, SET OF VARSTRING formats) :=
  524. StringLib.MatchTimeOfDay(time_text, formats);
  525. /**
  526. * Formats a date as a string.
  527. *
  528. * @param date The date to be converted.
  529. * @param format The format template to use for the conversion;
  530. * see strftime() for appropriate values. The maximum
  531. * length of the resulting string is 255 characters.
  532. * Optional; defaults to '%Y-%m-%d' which is YYYY-MM-DD.
  533. * @return Blank if date cannot be formatted, or the date in the
  534. * requested format.
  535. */
  536. EXPORT STRING DateToString(Date_t date, VARSTRING format = '%Y-%m-%d') :=
  537. TimeLib.DateToString(date, format);
  538. /**
  539. * Formats a time as a string.
  540. *
  541. * @param time The time to be converted.
  542. * @param format The format template to use for the conversion;
  543. * see strftime() for appropriate values. The maximum
  544. * length of the resulting string is 255 characters.
  545. * Optional; defaults to '%H:%M:%S' which is HH:MM:SS.
  546. * @return Blank if the time cannot be formatted, or the time
  547. * in the requested format.
  548. */
  549. EXPORT STRING TimeToString(Time_t time, VARSTRING format = '%H:%M:%S') :=
  550. TimeLib.TimeToString(time, format);
  551. /**
  552. * Converts a Seconds_t value into a human-readable string using a format template.
  553. *
  554. * @param seconds The seconds since epoch.
  555. * @param format The format template to use for the conversion; see
  556. * strftime() for appropriate values. The maximum length
  557. * of the resulting string is 255 characters.
  558. * Optional; defaults to '%Y-%m-%dT%H:%M:%S' which is YYYY-MM-DDTHH:MM:SS.
  559. * @return The converted seconds as a string.
  560. */
  561. EXPORT STRING SecondsToString(Seconds_t seconds, VARSTRING format = '%Y-%m-%dT%H:%M:%S') :=
  562. TimeLib.SecondsToString(seconds, format);
  563. /**
  564. * Formats a date as a string.
  565. *
  566. * @param date The date to be converted.
  567. * @param format The format the date is output in.
  568. * (See documentation for strftime)
  569. * @return Blank if date cannot be formatted, or the date in the
  570. * requested format.
  571. */
  572. EXPORT STRING ToString(Date_t date, VARSTRING format) := DateToString(date, format) : DEPRECATED('Replaced with DateToString() function');
  573. /**
  574. * Converts a date from one format to another
  575. *
  576. * @param date_text The string containing the date to be converted.
  577. * @param from_format The format the date is to be converted from.
  578. * @param to_format The format the date is to be converted to.
  579. * @return The converted string, or blank if it failed to match the format.
  580. */
  581. EXPORT STRING ConvertDateFormat(STRING date_text, VARSTRING from_format='%m/%d/%Y', VARSTRING to_format='%Y%m%d') :=
  582. DateToString(FromStringToDate(date_text, from_format), to_format);
  583. /**
  584. * Converts a date from one format to another
  585. *
  586. * @param date_text The string containing the date to be converted.
  587. * @param from_format The format the date is to be converted from.
  588. * @param to_format The format the date is to be converted to.
  589. * @return The converted string, or blank if it failed to match the format.
  590. */
  591. EXPORT STRING ConvertFormat(STRING date_text, VARSTRING from_format='%m/%d/%Y', VARSTRING to_format='%Y%m%d') :=
  592. ConvertDateFormat(date_text, from_format, to_format) : DEPRECATED('Replaced with ConvertDateFormat() function');
  593. /**
  594. * Converts a time from one format to another
  595. *
  596. * @param time_text The string containing the time to be converted.
  597. * @param from_format The format the time is to be converted from.
  598. * @param to_format The format the time is to be converted to.
  599. * @return The converted string, or blank if it failed to match the format.
  600. */
  601. EXPORT STRING ConvertTimeFormat(STRING time_text, VARSTRING from_format='%H%M%S', VARSTRING to_format='%H:%M:%S') :=
  602. TimeToString(FromStringToTime(time_text, from_format), to_format);
  603. /**
  604. * Converts a date that matches one of a set of formats to another.
  605. *
  606. * @param date_text The string containing the date to be converted.
  607. * @param from_formats The list of formats the date is to be converted from.
  608. * @param to_format The format the date is to be converted to.
  609. * @return The converted string, or blank if it failed to match the format.
  610. */
  611. EXPORT STRING ConvertDateFormatMultiple(STRING date_text, SET OF VARSTRING from_formats, VARSTRING to_format='%Y%m%d') := FUNCTION
  612. matchResult := MatchDateString(date_text, from_formats);
  613. reformatResult := IF(matchResult = (Date_t)0, '', DateToString(matchResult, to_format));
  614. RETURN reformatResult;
  615. END;
  616. /**
  617. * Converts a date that matches one of a set of formats to another.
  618. *
  619. * @param date_text The string containing the date to be converted.
  620. * @param from_formats The list of formats the date is to be converted from.
  621. * @param to_format The format the date is to be converted to.
  622. * @return The converted string, or blank if it failed to match the format.
  623. */
  624. EXPORT STRING ConvertFormatMultiple(STRING date_text, SET OF VARSTRING from_formats, VARSTRING to_format='%Y%m%d') :=
  625. ConvertDateFormatMultiple(date_text, from_formats, to_format) : DEPRECATED('Replaced with ConvertDateFormatMultiple() function');
  626. /**
  627. * Converts a time that matches one of a set of formats to another.
  628. *
  629. * @param time_text The string containing the time to be converted.
  630. * @param from_formats The list of formats the time is to be converted from.
  631. * @param to_format The format the time is to be converted to.
  632. * @return The converted string, or blank if it failed to match the format.
  633. */
  634. EXPORT STRING ConvertTimeFormatMultiple(STRING time_text, SET OF VARSTRING from_formats, VARSTRING to_format='%H:%m:%s') :=
  635. TimeToString(MatchTimeString(time_text, from_formats), to_format);
  636. /**
  637. * Adjusts a date by incrementing or decrementing year, month and/or day values.
  638. * The date must be in the Gregorian calendar after the year 1600.
  639. * If the new calculated date is invalid then it will be normalized according
  640. * to mktime() rules. Example: 20140130 + 1 month = 20140302.
  641. *
  642. * @param date The date to adjust.
  643. * @param year_delta The requested change to the year value;
  644. * optional, defaults to zero.
  645. * @param month_delta The requested change to the month value;
  646. * optional, defaults to zero.
  647. * @param day_delta The requested change to the day of month value;
  648. * optional, defaults to zero.
  649. * @return The adjusted Date_t value.
  650. */
  651. EXPORT Date_t AdjustDate(Date_t date,
  652. INTEGER2 year_delta = 0,
  653. INTEGER4 month_delta = 0,
  654. INTEGER4 day_delta = 0) :=
  655. TimeLib.AdjustDate(date, year_delta, month_delta, day_delta);
  656. /**
  657. * Adjusts a date by adding or subtracting seconds. The date must be in the
  658. * Gregorian calendar after the year 1600. If the new calculated
  659. * date is invalid then it will be normalized according to mktime() rules.
  660. * Example: 20140130 + 172800 seconds = 20140201.
  661. *
  662. * @param date The date to adjust.
  663. * @param seconds_delta The requested change to the date, in seconds.
  664. * @return The adjusted Date_t value.
  665. */
  666. EXPORT Date_t AdjustDateBySeconds(Date_t date, INTEGER4 seconds_delta) :=
  667. TimeLib.AdjustDateBySeconds(date, seconds_delta);
  668. /**
  669. * Adjusts a time by incrementing or decrementing hour, minute and/or second
  670. * values. If the new calculated time is invalid then it will be normalized
  671. * according to mktime() rules.
  672. *
  673. * @param time The time to adjust.
  674. * @param hour_delta The requested change to the hour value;
  675. * optional, defaults to zero.
  676. * @param minute_delta The requested change to the minute value;
  677. * optional, defaults to zero.
  678. * @param second_delta The requested change to the second of month value;
  679. * optional, defaults to zero.
  680. * @return The adjusted Time_t value.
  681. */
  682. EXPORT Time_t AdjustTime(Time_t time,
  683. INTEGER2 hour_delta = 0,
  684. INTEGER4 minute_delta = 0,
  685. INTEGER4 second_delta = 0) :=
  686. TimeLib.AdjustTime(time, hour_delta, minute_delta, second_delta);
  687. /**
  688. * Adjusts a time by adding or subtracting seconds. If the new calculated
  689. * time is invalid then it will be normalized according to mktime() rules.
  690. *
  691. * @param time The time to adjust.
  692. * @param seconds_delta The requested change to the time, in seconds.
  693. * @return The adjusted Time_t value.
  694. */
  695. EXPORT Time_t AdjustTimeBySeconds(Time_t time, INTEGER4 seconds_delta) :=
  696. TimeLib.AdjustTimeBySeconds(time, seconds_delta);
  697. /**
  698. * Adjusts a Seconds_t value by adding or subtracting years, months, days,
  699. * hours, minutes and/or seconds. This is performed by first converting the
  700. * seconds into a full date/time structure, applying any delta values to
  701. * individual date/time components, then converting the structure back to the
  702. * number of seconds. This interim date must lie within Gregorian calendar
  703. * after the year 1600. If the interim structure is found to have an invalid
  704. * date/time then it will be normalized according to mktime() rules. Therefore,
  705. * some delta values (such as "1 month") are actually relative to the value of
  706. * the seconds argument.
  707. *
  708. * @param seconds The number of seconds to adjust.
  709. * @param year_delta The requested change to the year value;
  710. * optional, defaults to zero.
  711. * @param month_delta The requested change to the month value;
  712. * optional, defaults to zero.
  713. * @param day_delta The requested change to the day of month value;
  714. * optional, defaults to zero.
  715. * @param hour_delta The requested change to the hour value;
  716. * optional, defaults to zero.
  717. * @param minute_delta The requested change to the minute value;
  718. * optional, defaults to zero.
  719. * @param second_delta The requested change to the second of month value;
  720. * optional, defaults to zero.
  721. * @return The adjusted Seconds_t value.
  722. */
  723. EXPORT Seconds_t AdjustSeconds(Seconds_t seconds,
  724. INTEGER2 year_delta = 0,
  725. INTEGER4 month_delta = 0,
  726. INTEGER4 day_delta = 0,
  727. INTEGER4 hour_delta = 0,
  728. INTEGER4 minute_delta = 0,
  729. INTEGER4 second_delta = 0) :=
  730. TimeLib.AdjustSeconds(seconds, year_delta, month_delta, day_delta, hour_delta, minute_delta, second_delta);
  731. /**
  732. * Adjusts a date by incrementing or decrementing months and/or years. This
  733. * routine uses the rule outlined in McGinn v. State, 46 Neb. 427, 65 N.W. 46 (1895):
  734. * "The term calendar month, whether employed in statutes or contracts, and
  735. * not appearing to have been used in a different sense, denotes a period
  736. * terminating with the day of the succeeding month numerically corresponding
  737. * to the day of its beginning, less one. If there be no corresponding day of
  738. * the succeeding month, it terminates with the last day thereof." The
  739. * internet suggests similar legal positions exist in the Commonwealth
  740. * and Germany. Note that day adjustments are performed after year and month
  741. * adjustments using the preceding rules. As an example, Jan. 31, 2014 + 1 month
  742. * will result in Feb. 28, 2014; Jan. 31, 2014 + 1 month + 1 day will result
  743. * in Mar. 1, 2014.
  744. *
  745. * @param date The date to adjust, in the Gregorian calendar after 1600.
  746. * @param year_delta The requested change to the year value;
  747. * optional, defaults to zero.
  748. * @param month_delta The requested change to the month value;
  749. * optional, defaults to zero.
  750. * @param day_delta The requested change to the day value;
  751. * optional, defaults to zero.
  752. * @return The adjusted Date_t value.
  753. */
  754. EXPORT Date_t AdjustCalendar(Date_t date,
  755. INTEGER2 year_delta = 0,
  756. INTEGER4 month_delta = 0,
  757. INTEGER4 day_delta = 0) :=
  758. TimeLib.AdjustCalendar(date, year_delta, month_delta, day_delta);
  759. /**
  760. * Returns a boolean indicating whether daylight savings time is currently
  761. * in effect locally.
  762. *
  763. * @return TRUE if daylight savings time is currently in effect, FALSE otherwise.
  764. */
  765. EXPORT BOOLEAN IsLocalDaylightSavingsInEffect() :=
  766. TimeLib.IsLocalDaylightSavingsInEffect();
  767. /**
  768. * Returns the offset (in seconds) of the time represented from UTC, with
  769. * positive values indicating locations east of the Prime Meridian. Given a
  770. * UTC time in seconds since epoch, you can find the local time by adding the
  771. * result of this function to the seconds.
  772. *
  773. * @return The number of seconds offset from UTC.
  774. */
  775. EXPORT INTEGER4 LocalTimeZoneOffset() :=
  776. TimeLib.LocalTimeZoneOffset();
  777. /**
  778. * Returns the current date.
  779. *
  780. * @param in_local_time TRUE if the returned value should be local to the
  781. * cluster computing the date, FALSE for UTC.
  782. * Optional, defaults to FALSE.
  783. * @return A Date_t representing the current date.
  784. */
  785. EXPORT Date_t CurrentDate(BOOLEAN in_local_time = FALSE) :=
  786. TimeLib.CurrentDate(in_local_time);
  787. /**
  788. * Returns the current date in the local time zone.
  789. *
  790. * @return A Date_t representing the current date.
  791. */
  792. EXPORT Date_t Today() := CurrentDate(TRUE);
  793. /**
  794. * Returns the current time of day
  795. *
  796. * @param in_local_time TRUE if the returned value should be local to the
  797. * cluster computing the time, FALSE for UTC.
  798. * Optional, defaults to FALSE.
  799. * @return A Time_t representing the current time of day.
  800. */
  801. EXPORT Time_t CurrentTime(BOOLEAN in_local_time = FALSE) :=
  802. TimeLib.CurrentTime(in_local_time);
  803. /**
  804. * Returns the current date and time as the number of seconds since epoch.
  805. *
  806. * @param in_local_time TRUE if the returned value should be local to the
  807. * cluster computing the time, FALSE for UTC.
  808. * Optional, defaults to FALSE.
  809. * @return A Seconds_t representing the current time in
  810. * UTC or local time, depending on the argument.
  811. */
  812. EXPORT Seconds_t CurrentSeconds(BOOLEAN in_local_time = FALSE) :=
  813. TimeLib.CurrentSeconds(in_local_time);
  814. /**
  815. * Returns the current date and time as the number of microseconds since epoch.
  816. *
  817. * @param in_local_time TRUE if the returned value should be local to the
  818. * cluster computing the time, FALSE for UTC.
  819. * Optional, defaults to FALSE.
  820. * @return A Timestamp_t representing the current time in
  821. * microseconds in UTC or local time, depending on
  822. * the argument.
  823. */
  824. EXPORT Timestamp_t CurrentTimestamp(BOOLEAN in_local_time = FALSE) :=
  825. TimeLib.CurrentTimestamp(in_local_time);
  826. /**
  827. * Returns the beginning and ending dates for the month surrounding the given date.
  828. *
  829. * @param as_of_date The reference date from which the month will be
  830. * calculated. This date must be a date within the
  831. * Gregorian calendar. Optional, defaults to the
  832. * current date in UTC.
  833. * @return Module with exported attributes for startDate and endDate.
  834. */
  835. EXPORT DatesForMonth(Date_t as_of_date = CurrentDate(FALSE)) := FUNCTION
  836. lastDay := TimeLib.GetLastDayOfMonth(as_of_date);
  837. firstDay := (lastDay DIV 100) * 100 + 1;
  838. result := MODULE
  839. EXPORT Date_t startDate := firstDay;
  840. EXPORT Date_t endDate := lastDay;
  841. END;
  842. RETURN result;
  843. END;
  844. /**
  845. * Returns the beginning and ending dates for the week surrounding the given date
  846. * (Sunday marks the beginning of a week).
  847. *
  848. * @param as_of_date The reference date from which the week will be
  849. * calculated. This date must be a date within the
  850. * Gregorian calendar. Optional, defaults to the
  851. * current date in UTC.
  852. * @return Module with exported attributes for startDate and endDate.
  853. */
  854. EXPORT DatesForWeek(Date_t as_of_date = CurrentDate(FALSE)) := FUNCTION
  855. lastWeekDates := ROW(TimeLib.DatesForWeek(as_of_date));
  856. result := MODULE
  857. EXPORT Date_t startDate := lastWeekDates.startDate;
  858. EXPORT Date_t endDate := lastWeekDates.endDate;
  859. END;
  860. RETURN result;
  861. END;
  862. /**
  863. * Tests whether a date is valid, both by range-checking the year and by
  864. * validating each of the other individual components.
  865. *
  866. * @param date The date to validate.
  867. * @param yearLowerBound The minimum acceptable year.
  868. * Optional; defaults to 1800.
  869. * @param yearUpperBound The maximum acceptable year.
  870. * Optional; defaults to 2100.
  871. * @return TRUE if the date is valid, FALSE otherwise.
  872. */
  873. EXPORT BOOLEAN IsValidDate(Date_t date,
  874. INTEGER2 yearLowerBound = 1800,
  875. INTEGER2 yearUpperBound = 2100) := FUNCTION
  876. yearInBounds := (Year(date) BETWEEN yearLowerBound AND yearUpperBound);
  877. monthInBounds := (Month(date) BETWEEN 1 AND 12);
  878. maxDayInMonth := CHOOSE(Month(date),31,IF(IsLeapYear(Year(date)),29,28),31,30,31,30,31,31,30,31,30,31);
  879. dayInBounds := (Day(date) BETWEEN 1 AND maxDayInMonth);
  880. RETURN yearInBounds AND monthInBounds AND dayInBounds;
  881. END;
  882. /**
  883. * Tests whether a date is valid in the Gregorian calendar. The year
  884. * must be between 1601 and 30827.
  885. *
  886. * @param date The Date_t to validate.
  887. * @return TRUE if the date is valid, FALSE otherwise.
  888. */
  889. EXPORT BOOLEAN IsValidGregorianDate(Date_t date) := FUNCTION
  890. yearInBounds := (Year(date) BETWEEN 1601 AND 30827);
  891. matchesNormalized := (date = AdjustDate(date)); // AdjustDate normalizes, so this is a validation check
  892. RETURN yearInBounds AND matchesNormalized;
  893. END;
  894. /**
  895. * Tests whether a time is valid.
  896. *
  897. * @param time The time to validate.
  898. * @return TRUE if the time is valid, FALSE otherwise.
  899. */
  900. EXPORT BOOLEAN IsValidTime(Time_t time) := FUNCTION
  901. hourInBounds := (Hour(time) BETWEEN 0 AND 23);
  902. minuteInBounds := (Minute(time) BETWEEN 0 AND 59);
  903. secondInBounds := (Second(time) BETWEEN 0 AND 59);
  904. RETURN hourInBounds AND minuteInBounds AND secondInBounds;
  905. END;
  906. //------------------------------------------------------------------------------
  907. // Transforms
  908. //------------------------------------------------------------------------------
  909. /**
  910. * A transform to create a Date_rec from the individual elements
  911. *
  912. * @param year The year
  913. * @param month The month (1-12).
  914. * @param day The day (1..daysInMonth).
  915. * @return A transform that creates a Date_rec containing the date.
  916. */
  917. EXPORT Date_rec CreateDate(INTEGER2 year, UNSIGNED1 month, UNSIGNED1 day) := TRANSFORM
  918. SELF.year := year;
  919. SELF.month := month;
  920. SELF.day := day;
  921. END;
  922. /**
  923. * A transform to create a Date_rec from a Seconds_t value.
  924. *
  925. * @param seconds The number seconds since epoch.
  926. * @return A transform that creates a Date_rec containing the date.
  927. */
  928. EXPORT Date_rec CreateDateFromSeconds(Seconds_t seconds) := TRANSFORM
  929. timeParts := SecondsToParts(seconds);
  930. SELF.year := timeParts.year;
  931. SELF.month := timeParts.month;
  932. SELF.day := timeParts.day;
  933. END;
  934. /**
  935. * A transform to create a Time_rec from the individual elements
  936. *
  937. * @param hour The hour (0-23).
  938. * @param minute The minute (0-59).
  939. * @param second The second (0-59).
  940. * @return A transform that creates a Time_rec containing the time of day.
  941. */
  942. EXPORT Time_rec CreateTime(UNSIGNED1 hour, UNSIGNED1 minute, UNSIGNED1 second) := TRANSFORM
  943. SELF.hour := hour;
  944. SELF.minute := minute;
  945. SELF.second := second;
  946. END;
  947. /**
  948. * A transform to create a Time_rec from a Seconds_t value.
  949. *
  950. * @param seconds The number seconds since epoch.
  951. * @return A transform that creates a Time_rec containing the time of day.
  952. */
  953. EXPORT Time_rec CreateTimeFromSeconds(Seconds_t seconds) := TRANSFORM
  954. timeParts := SecondsToParts(seconds);
  955. SELF.hour := timeParts.hour;
  956. SELF.minute := timeParts.minute;
  957. SELF.second := timeParts.second;
  958. END;
  959. /**
  960. * A transform to create a DateTime_rec from the individual elements
  961. *
  962. * @param year The year
  963. * @param month The month (1-12).
  964. * @param day The day (1..daysInMonth).
  965. * @param hour The hour (0-23).
  966. * @param minute The minute (0-59).
  967. * @param second The second (0-59).
  968. * @return A transform that creates a DateTime_rec containing date
  969. * and time components.
  970. */
  971. EXPORT DateTime_rec CreateDateTime(INTEGER2 year,
  972. UNSIGNED1 month,
  973. UNSIGNED1 day,
  974. UNSIGNED1 hour,
  975. UNSIGNED1 minute,
  976. UNSIGNED1 second) := TRANSFORM
  977. SELF.year := year;
  978. SELF.month := month;
  979. SELF.day := day;
  980. SELF.hour := hour;
  981. SELF.minute := minute;
  982. SELF.second := second;
  983. END;
  984. /**
  985. * A transform to create a DateTime_rec from a Seconds_t value.
  986. *
  987. * @param seconds The number seconds since epoch.
  988. * @return A transform that creates a DateTime_rec containing
  989. * date and time components.
  990. */
  991. EXPORT DateTime_rec CreateDateTimeFromSeconds(Seconds_t seconds) := TRANSFORM
  992. timeParts := SecondsToParts(seconds);
  993. SELF.year := timeParts.year;
  994. SELF.month := timeParts.month;
  995. SELF.day := timeParts.day;
  996. SELF.hour := timeParts.hour;
  997. SELF.minute := timeParts.minute;
  998. SELF.second := timeParts.second;
  999. END;
  1000. END; // Module