dateutil.inc 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435
  1. {$mode objfpc}
  2. {$h+}
  3. {
  4. This file is part of the Free Pascal run time library.
  5. Copyright (c) 1999-2000 by the Free Pascal development team
  6. Delphi/Kylix compatibility unit, provides Date/Time handling routines.
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit dateutils;
  14. interface
  15. {$ifndef FPUNONE}
  16. uses
  17. SysUtils, Math;
  18. { ---------------------------------------------------------------------
  19. Various constants
  20. ---------------------------------------------------------------------}
  21. const
  22. DaysPerWeek = 7;
  23. WeeksPerFortnight = 2;
  24. MonthsPerYear = 12;
  25. YearsPerDecade = 10;
  26. YearsPerCentury = 100;
  27. YearsPerMillennium = 1000;
  28. // ISO day numbers.
  29. DayMonday = 1;
  30. DayTuesday = 2;
  31. DayWednesday = 3;
  32. DayThursday = 4;
  33. DayFriday = 5;
  34. DaySaturday = 6;
  35. DaySunday = 7;
  36. // Fraction of a day
  37. OneHour = 1/HoursPerDay;
  38. OneMinute = 1/MinsPerDay;
  39. OneSecond = 1/SecsPerDay;
  40. OneMillisecond = 1/MSecsPerDay;
  41. { This is actual days per year but you need to know if it's a leap year}
  42. DaysPerYear: array [Boolean] of Word = (365, 366);
  43. { Used in RecodeDate, RecodeTime and RecodeDateTime for those datetime }
  44. { fields you want to leave alone }
  45. RecodeLeaveFieldAsIs = High(Word);
  46. { ---------------------------------------------------------------------
  47. Global variables used in this unit
  48. ---------------------------------------------------------------------}
  49. Const
  50. { Average over a 4 year span. Valid for next 100 years }
  51. ApproxDaysPerMonth: Double = 30.4375;
  52. ApproxDaysPerYear: Double = 365.25;
  53. { ---------------------------------------------------------------------
  54. Simple trimming functions.
  55. ---------------------------------------------------------------------}
  56. Function DateOf(const AValue: TDateTime): TDateTime;
  57. Function TimeOf(const AValue: TDateTime): TDateTime;
  58. { ---------------------------------------------------------------------
  59. Identification functions.
  60. ---------------------------------------------------------------------}
  61. Function IsInLeapYear(const AValue: TDateTime): Boolean;
  62. Function IsPM(const AValue: TDateTime): Boolean;
  63. Function IsValidDate(const AYear, AMonth, ADay: Word): Boolean;
  64. Function IsValidTime(const AHour, AMinute, ASecond, AMilliSecond: Word): Boolean;
  65. Function IsValidDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word): Boolean;
  66. Function IsValidDateDay(const AYear, ADayOfYear: Word): Boolean;
  67. Function IsValidDateWeek(const AYear, AWeekOfYear, ADayOfWeek: Word): Boolean;
  68. Function IsValidDateMonthWeek(const AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word): Boolean;
  69. { ---------------------------------------------------------------------
  70. Enumeration functions.
  71. ---------------------------------------------------------------------}
  72. Function WeeksInYear(const AValue: TDateTime): Word;
  73. Function WeeksInAYear(const AYear: Word): Word;
  74. Function DaysInYear(const AValue: TDateTime): Word;
  75. Function DaysInAYear(const AYear: Word): Word;
  76. Function DaysInMonth(const AValue: TDateTime): Word;
  77. Function DaysInAMonth(const AYear, AMonth: Word): Word;
  78. { ---------------------------------------------------------------------
  79. Variations on current date/time.
  80. ---------------------------------------------------------------------}
  81. Function Today: TDateTime;
  82. Function Yesterday: TDateTime;
  83. Function Tomorrow: TDateTime;
  84. Function IsToday(const AValue: TDateTime): Boolean;
  85. Function IsSameDay(const AValue, ABasis: TDateTime): Boolean;
  86. Function PreviousDayOfWeek (DayOfWeek : Word) : Word;
  87. { ---------------------------------------------------------------------
  88. Extraction functions.
  89. ---------------------------------------------------------------------}
  90. Function YearOf(const AValue: TDateTime): Word;
  91. Function MonthOf(const AValue: TDateTime): Word;
  92. Function WeekOf(const AValue: TDateTime): Word;
  93. Function DayOf(const AValue: TDateTime): Word;
  94. Function HourOf(const AValue: TDateTime): Word;
  95. Function MinuteOf(const AValue: TDateTime): Word;
  96. Function SecondOf(const AValue: TDateTime): Word;
  97. Function MilliSecondOf(const AValue: TDateTime): Word;
  98. { ---------------------------------------------------------------------
  99. Start/End of year functions.
  100. ---------------------------------------------------------------------}
  101. Function StartOfTheYear(const AValue: TDateTime): TDateTime;
  102. Function EndOfTheYear(const AValue: TDateTime): TDateTime;
  103. Function StartOfAYear(const AYear: Word): TDateTime;
  104. Function EndOfAYear(const AYear: Word): TDateTime;
  105. { ---------------------------------------------------------------------
  106. Start/End of month functions.
  107. ---------------------------------------------------------------------}
  108. Function StartOfTheMonth(const AValue: TDateTime): TDateTime;
  109. Function EndOfTheMonth(const AValue: TDateTime): TDateTime;
  110. Function StartOfAMonth(const AYear, AMonth: Word): TDateTime;
  111. Function EndOfAMonth(const AYear, AMonth: Word): TDateTime;
  112. { ---------------------------------------------------------------------
  113. Start/End of week functions.
  114. ---------------------------------------------------------------------}
  115. Function StartOfTheWeek(const AValue: TDateTime): TDateTime;
  116. Function EndOfTheWeek(const AValue: TDateTime): TDateTime;
  117. Function StartOfAWeek(const AYear, AWeekOfYear: Word; const ADayOfWeek: Word): TDateTime;
  118. Function StartOfAWeek(const AYear, AWeekOfYear: Word): TDateTime; // ADayOFWeek 1
  119. Function EndOfAWeek(const AYear, AWeekOfYear: Word; const ADayOfWeek: Word): TDateTime;
  120. Function EndOfAWeek(const AYear, AWeekOfYear: Word): TDateTime; // const ADayOfWeek: Word = 7
  121. { ---------------------------------------------------------------------
  122. Start/End of day functions.
  123. ---------------------------------------------------------------------}
  124. Function StartOfTheDay(const AValue: TDateTime): TDateTime;
  125. Function EndOfTheDay(const AValue: TDateTime): TDateTime;
  126. Function StartOfADay(const AYear, AMonth, ADay: Word): TDateTime; overload;
  127. Function StartOfADay(const AYear, ADayOfYear: Word): TDateTime; overload;
  128. Function EndOfADay(const AYear, AMonth, ADay: Word): TDateTime; overload;
  129. Function EndOfADay(const AYear, ADayOfYear: Word): TDateTime; overload;
  130. { ---------------------------------------------------------------------
  131. Part of year functions.
  132. ---------------------------------------------------------------------}
  133. Function MonthOfTheYear(const AValue: TDateTime): Word;
  134. Function WeekOfTheYear(const AValue: TDateTime): Word; overload;
  135. Function WeekOfTheYear(const AValue: TDateTime; out AYear: Word): Word; overload;
  136. Function DayOfTheYear(const AValue: TDateTime): Word;
  137. Function HourOfTheYear(const AValue: TDateTime): Word;
  138. Function MinuteOfTheYear(const AValue: TDateTime): LongWord;
  139. Function SecondOfTheYear(const AValue: TDateTime): LongWord;
  140. Function MilliSecondOfTheYear(const AValue: TDateTime): Int64;
  141. { ---------------------------------------------------------------------
  142. Part of month functions.
  143. ---------------------------------------------------------------------}
  144. Function WeekOfTheMonth(const AValue: TDateTime): Word; overload;
  145. Function WeekOfTheMonth(const AValue: TDateTime; out AYear, AMonth: Word): Word; overload;
  146. Function DayOfTheMonth(const AValue: TDateTime): Word;
  147. Function HourOfTheMonth(const AValue: TDateTime): Word;
  148. Function MinuteOfTheMonth(const AValue: TDateTime): Word;
  149. Function SecondOfTheMonth(const AValue: TDateTime): LongWord;
  150. Function MilliSecondOfTheMonth(const AValue: TDateTime): LongWord;
  151. { ---------------------------------------------------------------------
  152. Part of week functions.
  153. ---------------------------------------------------------------------}
  154. Function DayOfTheWeek(const AValue: TDateTime): Word;
  155. Function HourOfTheWeek(const AValue: TDateTime): Word;
  156. Function MinuteOfTheWeek(const AValue: TDateTime): Word;
  157. Function SecondOfTheWeek(const AValue: TDateTime): LongWord;
  158. Function MilliSecondOfTheWeek(const AValue: TDateTime): LongWord;
  159. { ---------------------------------------------------------------------
  160. Part of day functions.
  161. ---------------------------------------------------------------------}
  162. Function HourOfTheDay(const AValue: TDateTime): Word;
  163. Function MinuteOfTheDay(const AValue: TDateTime): Word;
  164. Function SecondOfTheDay(const AValue: TDateTime): LongWord;
  165. Function MilliSecondOfTheDay(const AValue: TDateTime): LongWord;
  166. { ---------------------------------------------------------------------
  167. Part of hour functions.
  168. ---------------------------------------------------------------------}
  169. Function MinuteOfTheHour(const AValue: TDateTime): Word;
  170. Function SecondOfTheHour(const AValue: TDateTime): Word;
  171. Function MilliSecondOfTheHour(const AValue: TDateTime): LongWord;
  172. { ---------------------------------------------------------------------
  173. Part of minute functions.
  174. ---------------------------------------------------------------------}
  175. Function SecondOfTheMinute(const AValue: TDateTime): Word;
  176. Function MilliSecondOfTheMinute(const AValue: TDateTime): LongWord;
  177. { ---------------------------------------------------------------------
  178. Part of second functions.
  179. ---------------------------------------------------------------------}
  180. Function MilliSecondOfTheSecond(const AValue: TDateTime): Word;
  181. { ---------------------------------------------------------------------
  182. Range checking functions.
  183. ---------------------------------------------------------------------}
  184. Function WithinPastYears(const ANow, AThen: TDateTime; const AYears: Integer): Boolean;
  185. Function WithinPastMonths(const ANow, AThen: TDateTime; const AMonths: Integer): Boolean;
  186. Function WithinPastWeeks(const ANow, AThen: TDateTime; const AWeeks: Integer): Boolean;
  187. Function WithinPastDays(const ANow, AThen: TDateTime; const ADays: Integer): Boolean;
  188. Function WithinPastHours(const ANow, AThen: TDateTime; const AHours: Int64): Boolean;
  189. Function WithinPastMinutes(const ANow, AThen: TDateTime; const AMinutes: Int64): Boolean;
  190. Function WithinPastSeconds(const ANow, AThen: TDateTime; const ASeconds: Int64): Boolean;
  191. Function WithinPastMilliSeconds(const ANow, AThen: TDateTime; const AMilliSeconds: Int64): Boolean;
  192. { ---------------------------------------------------------------------
  193. Period functions.
  194. ---------------------------------------------------------------------}
  195. Function YearsBetween(const ANow, AThen: TDateTime): Integer;
  196. Function MonthsBetween(const ANow, AThen: TDateTime): Integer;
  197. Function WeeksBetween(const ANow, AThen: TDateTime): Integer;
  198. Function DaysBetween(const ANow, AThen: TDateTime): Integer;
  199. Function HoursBetween(const ANow, AThen: TDateTime): Int64;
  200. Function MinutesBetween(const ANow, AThen: TDateTime): Int64;
  201. Function SecondsBetween(const ANow, AThen: TDateTime): Int64;
  202. Function MilliSecondsBetween(const ANow, AThen: TDateTime): Int64;
  203. { ---------------------------------------------------------------------
  204. Timespan in xxx functions.
  205. ---------------------------------------------------------------------}
  206. { YearSpan and MonthSpan are approximate values }
  207. Function YearSpan(const ANow, AThen: TDateTime): Double;
  208. Function MonthSpan(const ANow, AThen: TDateTime): Double;
  209. Function WeekSpan(const ANow, AThen: TDateTime): Double;
  210. Function DaySpan(const ANow, AThen: TDateTime): Double;
  211. Function HourSpan(const ANow, AThen: TDateTime): Double;
  212. Function MinuteSpan(const ANow, AThen: TDateTime): Double;
  213. Function SecondSpan(const ANow, AThen: TDateTime): Double;
  214. Function MilliSecondSpan(const ANow, AThen: TDateTime): Double;
  215. { ---------------------------------------------------------------------
  216. Increment/decrement functions.
  217. ---------------------------------------------------------------------}
  218. Function IncYear(const AValue: TDateTime; const ANumberOfYears: Integer ): TDateTime;
  219. Function IncYear(const AValue: TDateTime): TDateTime; // ; const ANumberOfYears: Integer = 1)
  220. // Function IncMonth is in SysUtils
  221. Function IncWeek(const AValue: TDateTime; const ANumberOfWeeks: Integer): TDateTime;
  222. Function IncWeek(const AValue: TDateTime): TDateTime; // ; const ANumberOfWeeks: Integer = 1)
  223. Function IncDay(const AValue: TDateTime; const ANumberOfDays: Integer): TDateTime;
  224. Function IncDay(const AValue: TDateTime): TDateTime; //; const ANumberOfDays: Integer = 1)
  225. Function IncHour(const AValue: TDateTime; const ANumberOfHours: Int64): TDateTime;
  226. Function IncHour(const AValue: TDateTime): TDateTime; //; const ANumberOfHours: Int64 = 1
  227. Function IncMinute(const AValue: TDateTime; const ANumberOfMinutes: Int64): TDateTime;
  228. Function IncMinute(const AValue: TDateTime): TDateTime; // ; const ANumberOfMinutes: Int64 = 1
  229. Function IncSecond(const AValue: TDateTime; const ANumberOfSeconds: Int64): TDateTime;
  230. Function IncSecond(const AValue: TDateTime): TDateTime; // ; const ANumberOfSeconds: Int64 = 1
  231. Function IncMilliSecond(const AValue: TDateTime; const ANumberOfMilliSeconds: Int64): TDateTime;
  232. Function IncMilliSecond(const AValue: TDateTime): TDateTime; // ; const ANumberOfMilliSeconds: Int64 = 1
  233. { ---------------------------------------------------------------------
  234. Encode/Decode of complete timestamp
  235. ---------------------------------------------------------------------}
  236. Function EncodeDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word): TDateTime;
  237. Procedure DecodeDateTime(const AValue: TDateTime; out AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word);
  238. Function TryEncodeDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; out AValue: TDateTime): Boolean;
  239. { ---------------------------------------------------------------------
  240. Encode/decode date, specifying week of year and day of week
  241. ---------------------------------------------------------------------}
  242. Function EncodeDateWeek(const AYear, AWeekOfYear: Word; const ADayOfWeek: Word): TDateTime;
  243. Function EncodeDateWeek(const AYear, AWeekOfYear: Word): TDateTime; //; const ADayOfWeek: Word = 1
  244. Procedure DecodeDateWeek(const AValue: TDateTime; out AYear, AWeekOfYear, ADayOfWeek: Word);
  245. Function TryEncodeDateWeek(const AYear, AWeekOfYear: Word; out AValue: TDateTime; const ADayOfWeek: Word): Boolean;
  246. Function TryEncodeDateWeek(const AYear, AWeekOfYear: Word; out AValue: TDateTime): Boolean; //; const ADayOfWeek: Word = 1
  247. { ---------------------------------------------------------------------
  248. Encode/decode date, specifying day of year
  249. ---------------------------------------------------------------------}
  250. Function EncodeDateDay(const AYear, ADayOfYear: Word): TDateTime;
  251. Procedure DecodeDateDay(const AValue: TDateTime; out AYear, ADayOfYear: Word);
  252. Function TryEncodeDateDay(const AYear, ADayOfYear: Word; out AValue: TDateTime): Boolean;
  253. { ---------------------------------------------------------------------
  254. Encode/decode date, specifying week of month
  255. ---------------------------------------------------------------------}
  256. Function EncodeDateMonthWeek(const AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word): TDateTime;
  257. Procedure DecodeDateMonthWeek(const AValue: TDateTime; out AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word);
  258. Function TryEncodeDateMonthWeek(const AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word; out AValue: TDateTime): Boolean;
  259. { ---------------------------------------------------------------------
  260. Replace given element with supplied value.
  261. ---------------------------------------------------------------------}
  262. Function RecodeYear(const AValue: TDateTime; const AYear: Word): TDateTime;
  263. Function RecodeMonth(const AValue: TDateTime; const AMonth: Word): TDateTime;
  264. Function RecodeDay(const AValue: TDateTime; const ADay: Word): TDateTime;
  265. Function RecodeHour(const AValue: TDateTime; const AHour: Word): TDateTime;
  266. Function RecodeMinute(const AValue: TDateTime; const AMinute: Word): TDateTime;
  267. Function RecodeSecond(const AValue: TDateTime; const ASecond: Word): TDateTime;
  268. Function RecodeMilliSecond(const AValue: TDateTime; const AMilliSecond: Word): TDateTime;
  269. Function RecodeDate(const AValue: TDateTime; const AYear, AMonth, ADay: Word): TDateTime;
  270. Function RecodeTime(const AValue: TDateTime; const AHour, AMinute, ASecond, AMilliSecond: Word): TDateTime;
  271. Function RecodeDateTime(const AValue: TDateTime; const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word): TDateTime;
  272. Function TryRecodeDateTime(const AValue: TDateTime; const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; out AResult: TDateTime): Boolean;
  273. { ---------------------------------------------------------------------
  274. Comparision of date/time
  275. ---------------------------------------------------------------------}
  276. Function CompareDateTime(const A, B: TDateTime): TValueRelationship;
  277. Function CompareDate(const A, B: TDateTime): TValueRelationship;
  278. Function CompareTime(const A, B: TDateTime): TValueRelationship;
  279. Function SameDateTime(const A, B: TDateTime): Boolean;
  280. Function SameDate(const A, B: TDateTime): Boolean;
  281. Function SameTime(const A, B: TDateTime): Boolean;
  282. { For a given date these Functions tell you the which day of the week of the
  283. month (or year). If its a Thursday, they will tell you if its the first,
  284. second, etc Thursday of the month (or year). Remember, even though its
  285. the first Thursday of the year it doesn't mean its the first week of the
  286. year. See ISO 8601 above for more information. }
  287. Function NthDayOfWeek(const AValue: TDateTime): Word;
  288. Procedure DecodeDayOfWeekInMonth(const AValue: TDateTime; out AYear, AMonth, ANthDayOfWeek, ADayOfWeek: Word);
  289. Function EncodeDayOfWeekInMonth(const AYear, AMonth, ANthDayOfWeek, ADayOfWeek: Word): TDateTime;
  290. Function TryEncodeDayOfWeekInMonth(const AYear, AMonth, ANthDayOfWeek, ADayOfWeek: Word; out AValue: TDateTime): Boolean;
  291. { ---------------------------------------------------------------------
  292. Exception throwing routines
  293. ---------------------------------------------------------------------}
  294. Procedure InvalidDateTimeError(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; const ABaseDate: TDateTime);
  295. Procedure InvalidDateTimeError(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word); // const ABaseDate: TDateTime = 0
  296. Procedure InvalidDateWeekError(const AYear, AWeekOfYear, ADayOfWeek: Word);
  297. Procedure InvalidDateDayError(const AYear, ADayOfYear: Word);
  298. Procedure InvalidDateMonthWeekError(const AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word);
  299. Procedure InvalidDayOfWeekInMonthError(const AYear, AMonth, ANthDayOfWeek, ADayOfWeek: Word);
  300. { ---------------------------------------------------------------------
  301. Julian and Modified Julian Date conversion support
  302. ---------------------------------------------------------------------}
  303. Function DateTimeToJulianDate(const AValue: TDateTime): Double;
  304. Function JulianDateToDateTime(const AValue: Double): TDateTime;
  305. Function TryJulianDateToDateTime(const AValue: Double; out ADateTime: TDateTime): Boolean;
  306. Function DateTimeToModifiedJulianDate(const AValue: TDateTime): Double;
  307. Function ModifiedJulianDateToDateTime(const AValue: Double): TDateTime;
  308. Function TryModifiedJulianDateToDateTime(const AValue: Double; out ADateTime: TDateTime): Boolean;
  309. { ---------------------------------------------------------------------
  310. Unix timestamp support.
  311. ---------------------------------------------------------------------}
  312. Function DateTimeToUnix(const AValue: TDateTime): Int64;
  313. Function UnixToDateTime(const AValue: Int64): TDateTime;
  314. Function UnixTimeStampToMac(const AValue: Int64): Int64;
  315. { ---------------------------------------------------------------------
  316. Mac timestamp support.
  317. ---------------------------------------------------------------------}
  318. Function DateTimeToMac(const AValue: TDateTime): Int64;
  319. Function MacToDateTime(const AValue: Int64): TDateTime;
  320. Function MacTimeStampToUnix(const AValue: Int64): Int64;
  321. { .....................................................................
  322. Dos <-> Delphi datetime support
  323. .....................................................................}
  324. Function DateTimeToDosDateTime(const AValue: TDateTime): longint;
  325. Function DosDateTimeToDateTime( AValue: longint): TDateTime;
  326. { ScanDateTime is a limited inverse of formatdatetime }
  327. function ScanDateTime(const Pattern:string;const s:string;const fmt:TFormatSettings;startpos:integer=1) : tdatetime; overload;
  328. function ScanDateTime(const Pattern:string;const s:string;startpos:integer=1) : tdatetime; overload;
  329. implementation
  330. uses sysconst;
  331. const
  332. TDateTimeEpsilon = 2.2204460493e-16;
  333. { ---------------------------------------------------------------------
  334. Auxiliary routines
  335. ---------------------------------------------------------------------}
  336. Procedure NotYetImplemented (FN : String);
  337. begin
  338. Raise Exception.CreateFmt('Function "%s" (dateutils) is not yet implemented',[FN]);
  339. end;
  340. { ---------------------------------------------------------------------
  341. Simple trimming functions.
  342. ---------------------------------------------------------------------}
  343. Function DateOf(const AValue: TDateTime): TDateTime; inline;
  344. begin
  345. Result:=Trunc(AValue);
  346. end;
  347. Function TimeOf(const AValue: TDateTime): TDateTime; inline;
  348. begin
  349. Result:=Frac(Avalue);
  350. end;
  351. { ---------------------------------------------------------------------
  352. Identification functions.
  353. ---------------------------------------------------------------------}
  354. Function IsInLeapYear(const AValue: TDateTime): Boolean;
  355. begin
  356. Result:=IsLeapYear(YearOf(AValue));
  357. end;
  358. Function IsPM(const AValue: TDateTime): Boolean; inline;
  359. begin
  360. Result:=(HourOf(AValue)>=12);
  361. end;
  362. Function IsValidDate(const AYear, AMonth, ADay: Word): Boolean;
  363. begin
  364. Result:=(AYear<>0) and (AYear<10000)
  365. and (AMonth in [1..12])
  366. and (ADay<>0) and (ADay<=MonthDays[IsleapYear(AYear),AMonth]);
  367. end;
  368. Function IsValidTime(const AHour, AMinute, ASecond, AMilliSecond: Word): Boolean;
  369. begin
  370. Result:=(AHour=HoursPerDay) and (AMinute=0) and (ASecond=0) and (AMillisecond=0);
  371. Result:=Result or
  372. ((AHour<HoursPerDay) and (AMinute<MinsPerHour) and (ASecond<SecsPerMin) and
  373. (AMillisecond<MSecsPerSec));
  374. end;
  375. Function IsValidDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word): Boolean;
  376. begin
  377. Result:=IsValidDate(AYear,AMonth,ADay) and
  378. IsValidTime(AHour,AMinute,ASecond,AMillisecond)
  379. end;
  380. Function IsValidDateDay(const AYear, ADayOfYear: Word): Boolean;
  381. begin
  382. Result:=(AYear<>0) and (ADayOfYear<>0) and (AYear<10000) and
  383. (ADayOfYear<=DaysPerYear[IsLeapYear(AYear)]);
  384. end;
  385. Function IsValidDateWeek(const AYear, AWeekOfYear, ADayOfWeek: Word): Boolean;
  386. begin
  387. Result:=(AYear<>0) and (AYear<10000)
  388. and (ADayOfWeek in [1..7])
  389. and (AWeekOfYear<>0)
  390. and (AWeekOfYear<=WeeksInaYear(AYear));
  391. { should we not also check whether the day of the week is not
  392. larger than the last day of the last week in the year 9999 ?? }
  393. end;
  394. Function IsValidDateMonthWeek(const AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word): Boolean;
  395. begin
  396. Result:=(AYear<>0) and (AYear<10000)
  397. and (AMonth in [1..12])
  398. and (AWeekOfMonth in [1..5])
  399. and (ADayOfWeek in [1..7]);
  400. end;
  401. { ---------------------------------------------------------------------
  402. Enumeration functions.
  403. ---------------------------------------------------------------------}
  404. Function WeeksInYear(const AValue: TDateTime): Word;
  405. begin
  406. Result:=WeeksInAYear(YearOf(AValue));
  407. end;
  408. Function WeeksInAYear(const AYear: Word): Word;
  409. Var
  410. DOW : Word;
  411. begin
  412. Result:=52;
  413. DOW:=DayOfTheWeek(StartOfAYear(AYear));
  414. If (DOW=4) or ((DOW=3) and IsLeapYear(AYear)) then
  415. Inc(Result);
  416. end;
  417. Function DaysInYear(const AValue: TDateTime): Word;
  418. begin
  419. Result:=DaysPerYear[IsLeapYear(YearOf(AValue))];
  420. end;
  421. Function DaysInAYear(const AYear: Word): Word;
  422. begin
  423. Result:=DaysPerYear[Isleapyear(AYear)];
  424. end;
  425. Function DaysInMonth(const AValue: TDateTime): Word;
  426. Var
  427. Y,M,D : Word;
  428. begin
  429. Decodedate(AValue,Y,M,D);
  430. Result:=MonthDays[IsLeapYear(Y),M];
  431. end;
  432. Function DaysInAMonth(const AYear, AMonth: Word): Word;
  433. begin
  434. Result:=MonthDays[IsLeapYear(AYear),AMonth];
  435. end;
  436. { ---------------------------------------------------------------------
  437. Variations on current date/time.
  438. ---------------------------------------------------------------------}
  439. Function Today: TDateTime; inline;
  440. begin
  441. Result:=Date();
  442. end;
  443. Function Yesterday: TDateTime;
  444. begin
  445. Result:=Date()-1;
  446. end;
  447. Function Tomorrow: TDateTime;
  448. begin
  449. Result:=Date()+1;
  450. end;
  451. Function IsToday(const AValue: TDateTime): Boolean;
  452. begin
  453. Result:=IsSameDay(AValue,Date());
  454. end;
  455. Function IsSameDay(const AValue, ABasis: TDateTime): Boolean;
  456. Var
  457. D : TDateTime;
  458. begin
  459. D:=AValue-Trunc(ABasis);
  460. Result:=(D>=0) and (D<1);
  461. end;
  462. const
  463. DOWMap: array [1..7] of Word = (7, 1, 2, 3, 4, 5, 6);
  464. Function PreviousDayOfWeek (DayOfWeek : Word) : Word;
  465. begin
  466. If Not (DayOfWeek in [1..7]) then
  467. Raise EConvertError.CreateFmt(SErrInvalidDayOfWeek,[DayOfWeek]);
  468. Result:=DOWMap[DayOfWeek];
  469. end;
  470. { ---------------------------------------------------------------------
  471. Extraction functions.
  472. ---------------------------------------------------------------------}
  473. Function YearOf(const AValue: TDateTime): Word;
  474. Var
  475. D,M : Word;
  476. begin
  477. DecodeDate(AValue,Result,D,M);
  478. end;
  479. Function MonthOf(const AValue: TDateTime): Word;
  480. Var
  481. Y,D : Word;
  482. begin
  483. DecodeDate(AValue,Y,Result,D);
  484. end;
  485. Function WeekOf(const AValue: TDateTime): Word; inline;
  486. begin
  487. Result:=WeekOfTheYear(AValue);
  488. end;
  489. Function DayOf(const AValue: TDateTime): Word;
  490. Var
  491. Y,M : Word;
  492. begin
  493. DecodeDate(AValue,Y,M,Result);
  494. end;
  495. Function HourOf(const AValue: TDateTime): Word;
  496. Var
  497. N,S,MS : Word;
  498. begin
  499. DecodeTime(AValue,Result,N,S,MS);
  500. end;
  501. Function MinuteOf(const AValue: TDateTime): Word;
  502. Var
  503. H,S,MS : Word;
  504. begin
  505. DecodeTime(AValue,H,Result,S,MS);
  506. end;
  507. Function SecondOf(const AValue: TDateTime): Word;
  508. Var
  509. H,N,MS : Word;
  510. begin
  511. DecodeTime(AValue,H,N,Result,MS);
  512. end;
  513. Function MilliSecondOf(const AValue: TDateTime): Word;
  514. Var
  515. H,N,S : Word;
  516. begin
  517. DecodeTime(AValue,H,N,S,Result);
  518. end;
  519. { ---------------------------------------------------------------------
  520. Start/End of year functions.
  521. ---------------------------------------------------------------------}
  522. Function StartOfTheYear(const AValue: TDateTime): TDateTime;
  523. begin
  524. Result:=EncodeDate(YearOf(AValue),1,1);
  525. end;
  526. Function EndOfTheYear(const AValue: TDateTime): TDateTime;
  527. begin
  528. Result:=EncodeDateTime(YearOf(AValue),12,31,23,59,59,999);
  529. end;
  530. Function StartOfAYear(const AYear: Word): TDateTime;
  531. begin
  532. Result:=EncodeDate(AYear,1,1);
  533. end;
  534. Function EndOfAYear(const AYear: Word): TDateTime;
  535. begin
  536. Result:=(EncodeDateTime(AYear,12,31,23,59,59,999));
  537. end;
  538. { ---------------------------------------------------------------------
  539. Start/End of month functions.
  540. ---------------------------------------------------------------------}
  541. Function StartOfTheMonth(const AValue: TDateTime): TDateTime;
  542. Var
  543. Y,M,D : Word;
  544. begin
  545. DecodeDate(AValue,Y,M,D);
  546. Result:=EncodeDate(Y,M,1);
  547. // MonthDays[IsLeapYear(Y),M])
  548. end;
  549. Function EndOfTheMonth(const AValue: TDateTime): TDateTime;
  550. Var
  551. Y,M,D : Word;
  552. begin
  553. DecodeDate(AValue,Y,M,D);
  554. Result:=EncodeDateTime(Y,M,MonthDays[IsLeapYear(Y),M],23,59,59,999);
  555. end;
  556. Function StartOfAMonth(const AYear, AMonth: Word): TDateTime; inline;
  557. begin
  558. Result:=EncodeDate(AYear,AMonth,1);
  559. end;
  560. Function EndOfAMonth(const AYear, AMonth: Word): TDateTime;
  561. begin
  562. Result:=EncodeDateTime(AYear,AMonth,MonthDays[IsLeapYear(AYear),AMonth],23,59,59,999);
  563. end;
  564. { ---------------------------------------------------------------------
  565. Start/End of week functions.
  566. ---------------------------------------------------------------------}
  567. Function StartOfTheWeek(const AValue: TDateTime): TDateTime;
  568. begin
  569. Result:=Trunc(AValue)-DayOfTheWeek(AValue)+1;
  570. end;
  571. Function EndOfTheWeek(const AValue: TDateTime): TDateTime;
  572. begin
  573. Result:=EndOfTheDay(AValue-DayOfTheWeek(AValue)+7);
  574. end;
  575. Function StartOfAWeek(const AYear, AWeekOfYear: Word; const ADayOfWeek: Word): TDateTime;
  576. begin
  577. Result:=EncodeDateWeek(AYear,AWeekOfYear,ADayOfWeek);
  578. end;
  579. Function StartOfAWeek(const AYear, AWeekOfYear: Word): TDateTime; inline; // ADayOFWeek 1
  580. begin
  581. Result:=StartOfAWeek(AYear,AWeekOfYear,1)
  582. end;
  583. Function EndOfAWeek(const AYear, AWeekOfYear: Word; const ADayOfWeek: Word): TDateTime; inline;
  584. begin
  585. Result := EndOfTheDay(EncodeDateWeek(AYear, AWeekOfYear, ADayOfWeek));
  586. end;
  587. Function EndOfAWeek(const AYear, AWeekOfYear: Word): TDateTime; // const ADayOfWeek: Word = 7
  588. begin
  589. Result:=EndOfAWeek(AYear,AWeekOfYear,7);
  590. end;
  591. { ---------------------------------------------------------------------
  592. Start/End of day functions.
  593. ---------------------------------------------------------------------}
  594. Function StartOfTheDay(const AValue: TDateTime): TDateTime; inline;
  595. begin
  596. StartOfTheDay:=Trunc(Avalue);
  597. end;
  598. Function EndOfTheDay(const AValue: TDateTime): TDateTime;
  599. Var
  600. Y,M,D : Word;
  601. begin
  602. DecodeDate(AValue,Y,M,D);
  603. Result:=EncodeDateTime(Y,M,D,23,59,59,999);
  604. end;
  605. Function StartOfADay(const AYear, AMonth, ADay: Word): TDateTime; inline;
  606. begin
  607. Result:=EncodeDate(AYear,AMonth,ADay);
  608. end;
  609. Function StartOfADay(const AYear, ADayOfYear: Word): TDateTime;
  610. begin
  611. Result:=StartOfAYear(AYear)+ADayOfYear-1;
  612. end;
  613. Function EndOfADay(const AYear, AMonth, ADay: Word): TDateTime; inline;
  614. begin
  615. Result:=EndOfTheDay(EncodeDate(AYear,AMonth,ADay));
  616. end;
  617. Function EndOfADay(const AYear, ADayOfYear: Word): TDateTime;
  618. begin
  619. Result:=StartOfAYear(AYear)+ADayOfYear-1+EncodeTime(23,59,59,999);
  620. end;
  621. { ---------------------------------------------------------------------
  622. Part of year functions.
  623. ---------------------------------------------------------------------}
  624. Function MonthOfTheYear(const AValue: TDateTime): Word; inline;
  625. begin
  626. Result:=MonthOf(AValue);
  627. end;
  628. Function WeekOfTheYear(const AValue: TDateTime): Word;
  629. Var
  630. Y,DOW : Word;
  631. begin
  632. DecodeDateWeek(AValue,Y,Result,DOW)
  633. end;
  634. Function WeekOfTheYear(const AValue: TDateTime; out AYear: Word): Word;
  635. Var
  636. DOW : Word;
  637. begin
  638. DecodeDateWeek(AValue,AYear,Result,DOW);
  639. end;
  640. Function DayOfTheYear(const AValue: TDateTime): Word;
  641. begin
  642. Result:=Trunc(AValue-StartOfTheYear(AValue)+1);
  643. end;
  644. Function HourOfTheYear(const AValue: TDateTime): Word;
  645. Var
  646. H,M,S,MS : Word;
  647. begin
  648. DecodeTime(AValue,H,M,S,MS);
  649. Result:=H+((DayOfTheYear(AValue)-1)*24);
  650. end;
  651. Function MinuteOfTheYear(const AValue: TDateTime): LongWord;
  652. Var
  653. H,M,S,MS : Word;
  654. begin
  655. DecodeTime(AValue,H,M,S,MS);
  656. Result:=M+(H+((DayOfTheYear(AValue)-1)*24))*60;
  657. end;
  658. Function SecondOfTheYear(const AValue: TDateTime): LongWord;
  659. Var
  660. H,M,S,MS : Word;
  661. begin
  662. DecodeTime(AValue,H,M,S,MS);
  663. Result:=(M+(H+((DayOfTheYear(AValue)-1)*24))*60)*60+S;
  664. end;
  665. Function MilliSecondOfTheYear(const AValue: TDateTime): Int64;
  666. Var
  667. H,M,S,MS : Word;
  668. begin
  669. DecodeTime(AValue,H,M,S,MS);
  670. Result:=((M+(H+((int64(DayOfTheYear(AValue))-1)*24))*60)*60+S)*1000+MS;
  671. end;
  672. { ---------------------------------------------------------------------
  673. Part of month functions.
  674. ---------------------------------------------------------------------}
  675. Function WeekOfTheMonth(const AValue: TDateTime): Word;
  676. var
  677. Y,M,DOW : word;
  678. begin
  679. DecodeDateMonthWeek(AValue,Y,M,Result,DOW);
  680. end;
  681. Function WeekOfTheMonth(const AValue: TDateTime; out AYear, AMonth: Word): Word;
  682. Var
  683. DOW : Word;
  684. begin
  685. DecodeDateMonthWeek(AValue,AYear,AMonth,Result,DOW);
  686. end;
  687. Function DayOfTheMonth(const AValue: TDateTime): Word;
  688. Var
  689. Y,M : Word;
  690. begin
  691. DecodeDate(AValue,Y,M,Result);
  692. end;
  693. Function HourOfTheMonth(const AValue: TDateTime): Word;
  694. Var
  695. Y,M,D,H,N,S,MS : Word;
  696. begin
  697. DecodeDateTime(AValue,Y,M,D,H,N,S,MS);
  698. Result:=(D-1)*24+H;
  699. end;
  700. Function MinuteOfTheMonth(const AValue: TDateTime): Word;
  701. Var
  702. Y,M,D,H,N,S,MS : Word;
  703. begin
  704. DecodeDateTime(AValue,Y,M,D,H,N,S,MS);
  705. Result:=((D-1)*24+H)*60+N;
  706. end;
  707. Function SecondOfTheMonth(const AValue: TDateTime): LongWord;
  708. Var
  709. Y,M,D,H,N,S,MS : Word;
  710. begin
  711. DecodeDateTime(AValue,Y,M,D,H,N,S,MS);
  712. Result:=(((D-1)*24+H)*60+N)*60+S;
  713. end;
  714. Function MilliSecondOfTheMonth(const AValue: TDateTime): LongWord;
  715. Var
  716. Y,M,D,H,N,S,MS : Word;
  717. begin
  718. DecodeDateTime(AValue,Y,M,D,H,N,S,MS);
  719. Result:=((((D-1)*24+H)*60+N)*60+S)*1000+MS;
  720. end;
  721. { ---------------------------------------------------------------------
  722. Part of week functions.
  723. ---------------------------------------------------------------------}
  724. Function DayOfTheWeek(const AValue: TDateTime): Word;
  725. begin
  726. Result:=DowMAP[DayOfWeek(AValue)];
  727. end;
  728. Function HourOfTheWeek(const AValue: TDateTime): Word;
  729. Var
  730. H,M,S,MS : Word;
  731. begin
  732. DecodeTime(AValue,H,M,S,MS);
  733. Result:=(DayOfTheWeek(AValue)-1)*24+H;
  734. end;
  735. Function MinuteOfTheWeek(const AValue: TDateTime): Word;
  736. Var
  737. H,M,S,MS : Word;
  738. begin
  739. DecodeTime(AValue,H,M,S,MS);
  740. Result:=((DayOfTheWeek(AValue)-1)*24+H)*60+M;
  741. end;
  742. Function SecondOfTheWeek(const AValue: TDateTime): LongWord;
  743. Var
  744. H,M,S,MS : Word;
  745. begin
  746. DecodeTime(AValue,H,M,S,MS);
  747. Result:=(((DayOfTheWeek(AValue)-1)*24+H)*60+M)*60+S;
  748. end;
  749. Function MilliSecondOfTheWeek(const AValue: TDateTime): LongWord;
  750. Var
  751. H,M,S,MS : Word;
  752. begin
  753. DecodeTime(AValue,H,M,S,MS);
  754. Result:=((((DayOfTheWeek(AValue)-1)*24+H)*60+M)*60+S)*1000+MS;
  755. end;
  756. { ---------------------------------------------------------------------
  757. Part of day functions.
  758. ---------------------------------------------------------------------}
  759. Function HourOfTheDay(const AValue: TDateTime): Word; inline;
  760. begin
  761. Result:=HourOf(AValue);
  762. end;
  763. Function MinuteOfTheDay(const AValue: TDateTime): Word;
  764. Var
  765. H,M,S,MS : Word;
  766. begin
  767. DecodeTime(AValue,H,M,S,MS);
  768. Result:=(H*60)+M;
  769. end;
  770. Function SecondOfTheDay(const AValue: TDateTime): LongWord;
  771. Var
  772. H,M,S,MS : Word;
  773. begin
  774. DecodeTime(AValue,H,M,S,MS);
  775. Result:=((H*60)+M)*60+S;
  776. end;
  777. Function MilliSecondOfTheDay(const AValue: TDateTime): LongWord;
  778. Var
  779. H,M,S,MS : Word;
  780. begin
  781. DecodeTime(AValue,H,M,S,MS);
  782. Result:=(((H*60)+M)*60+S)*1000+MS;
  783. end;
  784. { ---------------------------------------------------------------------
  785. Part of hour functions.
  786. ---------------------------------------------------------------------}
  787. Function MinuteOfTheHour(const AValue: TDateTime): Word; inline;
  788. begin
  789. Result:=MinuteOf(AValue);
  790. end;
  791. Function SecondOfTheHour(const AValue: TDateTime): Word;
  792. Var
  793. H,S,M,MS : Word;
  794. begin
  795. DecodeTime(AValue,H,M,S,MS);
  796. Result:=M*60+S;
  797. end;
  798. Function MilliSecondOfTheHour(const AValue: TDateTime): LongWord;
  799. Var
  800. H,S,M,MS : Word;
  801. begin
  802. DecodeTime(AValue,H,M,S,MS);
  803. Result:=(M*60+S)*1000+MS;
  804. end;
  805. { ---------------------------------------------------------------------
  806. Part of minute functions.
  807. ---------------------------------------------------------------------}
  808. Function SecondOfTheMinute(const AValue: TDateTime): Word; inline;
  809. begin
  810. Result:=SecondOf(AValue);
  811. end;
  812. Function MilliSecondOfTheMinute(const AValue: TDateTime): LongWord;
  813. Var
  814. H,S,M,MS : Word;
  815. begin
  816. DecodeTime(AValue,H,M,S,MS);
  817. Result:=S*1000+MS;
  818. end;
  819. { ---------------------------------------------------------------------
  820. Part of second functions.
  821. ---------------------------------------------------------------------}
  822. Function MilliSecondOfTheSecond(const AValue: TDateTime): Word; inline;
  823. begin
  824. Result:=MilliSecondOf(AValue);
  825. end;
  826. { ---------------------------------------------------------------------
  827. Range checking functions.
  828. ---------------------------------------------------------------------}
  829. Function WithinPastYears(const ANow, AThen: TDateTime; const AYears: Integer): Boolean; inline;
  830. begin
  831. Result:=YearsBetween(ANow,AThen)<=AYears;
  832. end;
  833. Function WithinPastMonths(const ANow, AThen: TDateTime; const AMonths: Integer): Boolean; inline;
  834. begin
  835. Result:=MonthsBetween(ANow,AThen)<=AMonths;
  836. end;
  837. Function WithinPastWeeks(const ANow, AThen: TDateTime; const AWeeks: Integer): Boolean; inline;
  838. begin
  839. Result:=WeeksBetween(ANow,AThen)<=AWeeks;
  840. end;
  841. Function WithinPastDays(const ANow, AThen: TDateTime; const ADays: Integer): Boolean; inline;
  842. begin
  843. Result:=DaysBetween(ANow,AThen)<=ADays;
  844. end;
  845. Function WithinPastHours(const ANow, AThen: TDateTime; const AHours: Int64): Boolean; inline;
  846. begin
  847. Result:=HoursBetween(ANow,AThen)<=AHours;
  848. end;
  849. Function WithinPastMinutes(const ANow, AThen: TDateTime; const AMinutes: Int64): Boolean; inline;
  850. begin
  851. Result:=MinutesBetween(ANow,AThen)<=AMinutes;
  852. end;
  853. Function WithinPastSeconds(const ANow, AThen: TDateTime; const ASeconds: Int64): Boolean; inline;
  854. begin
  855. Result:=SecondsBetween(ANow,Athen)<=ASeconds;
  856. end;
  857. Function WithinPastMilliSeconds(const ANow, AThen: TDateTime; const AMilliSeconds: Int64): Boolean; inline;
  858. begin
  859. Result:=MilliSecondsBetween(ANow,AThen)<=AMilliSeconds;
  860. end;
  861. { ---------------------------------------------------------------------
  862. Period functions.
  863. ---------------------------------------------------------------------}
  864. {
  865. These functions are declared as approximate by Borland.
  866. A bit strange, since it can be calculated exactly ?
  867. -- No, because you need rounding or truncating (JM)
  868. }
  869. Function DateTimeDiff(const ANow, AThen: TDateTime): TDateTime;
  870. begin
  871. Result:= ANow - AThen;
  872. if (ANow>0) and (AThen<0) then
  873. Result:=Result-0.5
  874. else if (ANow<-1.0) and (AThen>-1.0) then
  875. Result:=Result+0.5;
  876. end;
  877. Function YearsBetween(const ANow, AThen: TDateTime): Integer;
  878. begin
  879. Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)/ApproxDaysPerYear);
  880. end;
  881. Function MonthsBetween(const ANow, AThen: TDateTime): Integer;
  882. begin
  883. Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)/ApproxDaysPerMonth);
  884. end;
  885. Function WeeksBetween(const ANow, AThen: TDateTime): Integer;
  886. begin
  887. Result:=Trunc(Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon) div 7;
  888. end;
  889. Function DaysBetween(const ANow, AThen: TDateTime): Integer;
  890. begin
  891. Result:=Trunc(Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon);
  892. end;
  893. Function HoursBetween(const ANow, AThen: TDateTime): Int64;
  894. begin
  895. Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*HoursPerDay);
  896. end;
  897. Function MinutesBetween(const ANow, AThen: TDateTime): Int64;
  898. begin
  899. Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*MinsPerDay);
  900. end;
  901. Function SecondsBetween(const ANow, AThen: TDateTime): Int64;
  902. begin
  903. Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*SecsPerDay);
  904. end;
  905. Function MilliSecondsBetween(const ANow, AThen: TDateTime): Int64;
  906. begin
  907. Result:=Trunc((Abs(DateTimeDiff(ANow,AThen))+TDateTimeEpsilon)*MSecsPerDay);
  908. end;
  909. { ---------------------------------------------------------------------
  910. Timespan in xxx functions.
  911. ---------------------------------------------------------------------}
  912. Function YearSpan(const ANow, AThen: TDateTime): Double;
  913. begin
  914. Result:=Abs(DateTimeDiff(ANow,AThen))/ApproxDaysPerYear;
  915. end;
  916. Function MonthSpan(const ANow, AThen: TDateTime): Double;
  917. begin
  918. Result:=Abs(DateTimeDiff(ANow,AThen))/ApproxDaysPerMonth;
  919. end;
  920. Function WeekSpan(const ANow, AThen: TDateTime): Double;
  921. begin
  922. Result:=Abs(DateTimeDiff(ANow,AThen)) / 7
  923. end;
  924. Function DaySpan(const ANow, AThen: TDateTime): Double;
  925. begin
  926. Result:=Abs(DateTimeDiff(ANow,AThen));
  927. end;
  928. Function HourSpan(const ANow, AThen: TDateTime): Double;
  929. begin
  930. Result:=Abs(DateTimeDiff(ANow,AThen))*HoursPerDay;
  931. end;
  932. Function MinuteSpan(const ANow, AThen: TDateTime): Double;
  933. begin
  934. Result:=Abs(DateTimeDiff(ANow,AThen))*MinsPerDay;
  935. end;
  936. Function SecondSpan(const ANow, AThen: TDateTime): Double;
  937. begin
  938. Result:=Abs(DateTimeDiff(ANow,AThen))*SecsPerDay;
  939. end;
  940. Function MilliSecondSpan(const ANow, AThen: TDateTime): Double;
  941. begin
  942. Result:=Abs(DateTimeDiff(ANow,AThen))*MSecsPerDay;
  943. end;
  944. { ---------------------------------------------------------------------
  945. Increment/decrement functions.
  946. ---------------------------------------------------------------------}
  947. Procedure MaybeSkipTimeWarp(OldDate: TDateTime; var NewDate: TDateTime);
  948. begin
  949. if (OldDate>0) and (NewDate<0) then
  950. NewDate:=NewDate-0.5
  951. else if (OldDate<-1.0) and (NewDate>-1.0) then
  952. NewDate:=NewDate+0.5;
  953. end;
  954. Function IncYear(const AValue: TDateTime; const ANumberOfYears: Integer ): TDateTime;
  955. Var
  956. Y,M,D,H,N,S,MS : Word;
  957. begin
  958. DecodeDateTime(AValue,Y,M,D,H,N,S,MS);
  959. Y:=Y+ANumberOfYears;
  960. If (M=2) and (D=29) And (Not IsLeapYear(Y)) then
  961. D:=28;
  962. Result:=EncodeDateTime(Y,M,D,H,N,S,MS);
  963. end;
  964. Function IncYear(const AValue: TDateTime): TDateTime; // ; const ANumberOfYears: Integer = 1)
  965. begin
  966. Result:=IncYear(Avalue,1);
  967. end;
  968. Function IncWeek(const AValue: TDateTime; const ANumberOfWeeks: Integer): TDateTime;
  969. begin
  970. Result:=AValue+ANumberOfWeeks*7;
  971. MaybeSkipTimeWarp(AValue,Result);
  972. end;
  973. Function IncWeek(const AValue: TDateTime): TDateTime; // ; const ANumberOfWeeks: Integer = 1)
  974. begin
  975. Result:=IncWeek(Avalue,1);
  976. end;
  977. Function IncDay(const AValue: TDateTime; const ANumberOfDays: Integer): TDateTime;
  978. begin
  979. Result:=AValue+ANumberOfDays;
  980. MaybeSkipTimeWarp(AValue,Result);
  981. end;
  982. Function IncDay(const AValue: TDateTime): TDateTime; //; const ANumberOfDays: Integer = 1)
  983. begin
  984. Result:=IncDay(Avalue,1);
  985. end;
  986. Function IncHour(const AValue: TDateTime; const ANumberOfHours: Int64): TDateTime;
  987. begin
  988. Result:=AValue+ANumberOfHours/HoursPerDay;
  989. MaybeSkipTimeWarp(AValue,Result);
  990. end;
  991. Function IncHour(const AValue: TDateTime): TDateTime; //; const ANumberOfHours: Int64 = 1
  992. begin
  993. Result:=IncHour(AValue,1);
  994. end;
  995. Function IncMinute(const AValue: TDateTime; const ANumberOfMinutes: Int64): TDateTime;
  996. begin
  997. Result:=AValue+ANumberOfMinutes / MinsPerDay;
  998. MaybeSkipTimeWarp(AValue,Result);
  999. end;
  1000. Function IncMinute(const AValue: TDateTime): TDateTime; // ; const ANumberOfMinutes: Int64 = 1
  1001. begin
  1002. Result:=IncMinute(AValue,1);
  1003. end;
  1004. Function IncSecond(const AValue: TDateTime; const ANumberOfSeconds: Int64): TDateTime;
  1005. begin
  1006. Result:=AValue+ANumberOfSeconds / SecsPerDay;
  1007. MaybeSkipTimeWarp(AValue,Result);
  1008. end;
  1009. Function IncSecond(const AValue: TDateTime): TDateTime; // ; const ANumberOfSeconds: Int64 = 1
  1010. begin
  1011. Result:=IncSecond(Avalue,1);
  1012. end;
  1013. Function IncMilliSecond(const AValue: TDateTime; const ANumberOfMilliSeconds: Int64): TDateTime;
  1014. begin
  1015. Result:=AValue+ANumberOfMilliSeconds/MSecsPerDay;
  1016. MaybeSkipTimeWarp(AValue,Result);
  1017. end;
  1018. Function IncMilliSecond(const AValue: TDateTime): TDateTime; // ; const ANumberOfMilliSeconds: Int64 = 1
  1019. begin
  1020. Result:=IncMilliSecond(AValue,1);
  1021. end;
  1022. { ---------------------------------------------------------------------
  1023. Encode/Decode of complete timestamp
  1024. ---------------------------------------------------------------------}
  1025. Function EncodeDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word): TDateTime;
  1026. begin
  1027. If Not TryEncodeDateTime(AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond,Result) then
  1028. InvalidDateTimeError(AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond)
  1029. end;
  1030. Procedure DecodeDateTime(const AValue: TDateTime; out AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word);
  1031. begin
  1032. DecodeTime(AValue,AHour,AMinute,ASecond,AMilliSecond);
  1033. if AHour=24 then // can happen due rounding issues mantis 17123
  1034. begin
  1035. AHour:=0; // rest is already zero
  1036. DecodeDate(round(AValue),AYear,AMonth,ADay);
  1037. end
  1038. else
  1039. DecodeDate(AValue,AYear,AMonth,ADay);
  1040. end;
  1041. Function TryEncodeDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; out AValue: TDateTime): Boolean;
  1042. Var
  1043. tmp : TDateTime;
  1044. begin
  1045. Result:=TryEncodeDate(AYear,AMonth,ADay,AValue);
  1046. Result:=Result and TryEncodeTime(AHour,AMinute,ASecond,Amillisecond,Tmp);
  1047. If Result then
  1048. Avalue:=ComposeDateTime(AValue,Tmp);
  1049. end;
  1050. { ---------------------------------------------------------------------
  1051. Encode/decode date, specifying week of year and day of week
  1052. ---------------------------------------------------------------------}
  1053. Function EncodeDateWeek(const AYear, AWeekOfYear: Word; const ADayOfWeek: Word): TDateTime;
  1054. begin
  1055. If Not TryEncodeDateWeek(AYear,AWeekOfYear,Result,ADayOfWeek) then
  1056. InvalidDateWeekError(AYear,AWeekOfYear,ADayOfWeek);
  1057. end;
  1058. Function EncodeDateWeek(const AYear, AWeekOfYear: Word): TDateTime; //; const ADayOfWeek: Word = 1
  1059. begin
  1060. Result := EncodeDateWeek(AYear,AWeekOfYear,1);
  1061. end;
  1062. Procedure DecodeDateWeek(const AValue: TDateTime; out AYear, AWeekOfYear, ADayOfWeek: Word);
  1063. var
  1064. DOY : Integer;
  1065. D: Word;
  1066. YS : TDateTime;
  1067. YSDOW, YEDOW: Word;
  1068. begin
  1069. AYear:=YearOf(AValue);
  1070. // Correct to ISO DOW
  1071. ADayOfWeek:=DayOfWeek(AValue)-1;
  1072. If ADAyOfWeek=0 then
  1073. ADayofweek:=7;
  1074. YS:=StartOfAYear(AYear);
  1075. DOY:=Trunc(AValue-YS)+1;
  1076. YSDOW:=DayOfTheWeek(YS);
  1077. // Correct week if later than wednesday. First week never starts later than wednesday
  1078. if (YSDOW<5) then
  1079. Inc(DOY,YSDOW-1)
  1080. else
  1081. Dec(DOY,8-YSDOW);
  1082. if (DOY<=0) then // Day is in last week of previous year.
  1083. DecodeDateWeek(YS-1,AYear,AWeekOfYear,D)
  1084. else
  1085. begin
  1086. AWeekOfYear:=DOY div 7;
  1087. if ((DOY mod 7)<>0) then
  1088. Inc(AWeekOfYear);
  1089. if (AWeekOfYear>52) then // Maybe in first week of next year ?
  1090. begin
  1091. YEDOW:=YSDOW;
  1092. if IsLeapYear(AYear) then
  1093. begin
  1094. Inc(YEDOW);
  1095. if (YEDOW>7) then
  1096. YEDOW:=1
  1097. else
  1098. end;
  1099. if (YEDOW<4) then // Really next year.
  1100. begin
  1101. Inc(AYear);
  1102. AWeekOfYear:=1;
  1103. end;
  1104. end;
  1105. end;
  1106. end;
  1107. Function TryEncodeDateWeek(const AYear, AWeekOfYear: Word; out AValue: TDateTime; const ADayOfWeek: Word): Boolean;
  1108. Var
  1109. DOW : Word;
  1110. Rest : Integer;
  1111. begin
  1112. Result:=IsValidDateWeek(Ayear,AWeekOfYear,ADayOfWeek);
  1113. If Result then
  1114. begin
  1115. AValue:=EncodeDate(AYear,1,1)+(7*(AWeekOfYear-1));
  1116. DOW:=DayOfTheWeek(AValue);
  1117. Rest:=ADayOfWeek-DOW;
  1118. If (DOW>4) then
  1119. Inc(Rest,7);
  1120. AValue:=AValue+Rest;
  1121. end;
  1122. end;
  1123. Function TryEncodeDateWeek(const AYear, AWeekOfYear: Word; out AValue: TDateTime): Boolean; //; const ADayOfWeek: Word = 1
  1124. begin
  1125. Result:=TryEncodeDateWeek(AYear,AWeekOfYear,AValue,1);
  1126. end;
  1127. { ---------------------------------------------------------------------
  1128. Encode/decode date, specifying day of year
  1129. ---------------------------------------------------------------------}
  1130. Function EncodeDateDay(const AYear, ADayOfYear: Word): TDateTime;
  1131. begin
  1132. If Not TryEncodeDateDay(AYear,ADayOfYear,Result) then
  1133. InvalidDateDayError(AYear,ADayOfYear);
  1134. end;
  1135. Procedure DecodeDateDay(const AValue: TDateTime; out AYear, ADayOfYear: Word);
  1136. Var
  1137. M,D : Word;
  1138. begin
  1139. DecodeDate(AValue,AYear,M,D);
  1140. ADayOfyear:=Trunc(AValue-EncodeDate(AYear,1,1))+1;
  1141. end;
  1142. Function TryEncodeDateDay(const AYear, ADayOfYear: Word; out AValue: TDateTime): Boolean;
  1143. begin
  1144. Result:=(ADayOfYear<>0) and (ADayOfYear<=DaysPerYear [IsleapYear(AYear)]);
  1145. If Result then
  1146. AValue:=EncodeDate(AYear,1,1)+ADayOfYear-1;
  1147. end;
  1148. { ---------------------------------------------------------------------
  1149. Encode/decode date, specifying week of month
  1150. ---------------------------------------------------------------------}
  1151. Function EncodeDateMonthWeek(const AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word): TDateTime;
  1152. begin
  1153. If Not TryEncodeDateMonthWeek(Ayear,AMonth,AWeekOfMonth,ADayOfWeek,Result) then
  1154. InvalidDateMonthWeekError(AYear,AMonth,AWeekOfMonth,ADayOfWeek);
  1155. end;
  1156. Procedure DecodeDateMonthWeek(const AValue: TDateTime; out AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word);
  1157. Var
  1158. D,SDOM,EDOM : Word;
  1159. SOM : TdateTime;
  1160. DOM : Integer;
  1161. begin
  1162. DecodeDate(AValue,AYear,AMonth,D);
  1163. ADayOfWeek:=DayOfTheWeek(AValue);
  1164. SOM:=EncodeDate(Ayear,Amonth,1);
  1165. SDOM:=DayOfTheWeek(SOM);
  1166. DOM:=D-1+SDOM;
  1167. If SDOM>4 then
  1168. Dec(DOM,7);
  1169. // Too early in the month. First full week is next week, day is after thursday.
  1170. If DOM<=0 Then
  1171. DecodeDateMonthWeek(SOM-1,AYear,AMonth,AWeekOfMonth,D)
  1172. else
  1173. begin
  1174. AWeekOfMonth:=(DOM div 7)+Ord((DOM mod 7)<>0);
  1175. EDOM:=DayOfTheWeek(EndOfAMonth(Ayear,AMonth));
  1176. // In last days of last long week, so in next month...
  1177. If (EDOM<4) and ((DaysInAMonth(AYear,Amonth)-D)<EDOM) then
  1178. begin
  1179. AWeekOfMonth:=1;
  1180. Inc(AMonth);
  1181. If (AMonth=13) then
  1182. begin
  1183. AMonth:=1;
  1184. Inc(AYear);
  1185. end;
  1186. end;
  1187. end;
  1188. end;
  1189. Function TryEncodeDateMonthWeek(const AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word; out AValue: TDateTime): Boolean;
  1190. var
  1191. S : Word;
  1192. DOM : Integer;
  1193. begin
  1194. Result:=IsValidDateMonthWeek(AYear,AMonth,AWeekOfMonth,ADayOfWeek);
  1195. if Result then
  1196. begin
  1197. AValue:=EncodeDate(AYear,AMonth,1);
  1198. DOM:=(AWeekOfMonth-1)*7+ADayOfWeek-1;
  1199. { Correct for first week in last month.}
  1200. S:=DayOfTheWeek(AValue);
  1201. Dec(DOM,S-1);
  1202. if S in [DayFriday..DaySunday] then
  1203. Inc(DOM,7);
  1204. AValue:=AValue+DOM;
  1205. end;
  1206. end;
  1207. { ---------------------------------------------------------------------
  1208. Replace given element with supplied value.
  1209. ---------------------------------------------------------------------}
  1210. Const
  1211. LFAI = RecodeLeaveFieldAsIS; // Less typing, readable code
  1212. {
  1213. Note: We have little choice but to implement it like Borland did:
  1214. If AValue contains some 'wrong' value, it will throw an error.
  1215. To simulate this we'd have to check in each function whether
  1216. both arguments are correct. To avoid it, all is routed through
  1217. the 'central' RecodeDateTime function as in Borland's implementation.
  1218. }
  1219. Function RecodeYear(const AValue: TDateTime; const AYear: Word): TDateTime;
  1220. begin
  1221. Result := RecodeDateTime(AValue,AYear,LFAI,LFAI,LFAI,LFAI,LFAI,LFAI);
  1222. end;
  1223. Function RecodeMonth(const AValue: TDateTime; const AMonth: Word): TDateTime;
  1224. begin
  1225. Result := RecodeDateTime(AValue,LFAI,AMonth,LFAI,LFAI,LFAI,LFAI,LFAI);
  1226. end;
  1227. Function RecodeDay(const AValue: TDateTime; const ADay: Word): TDateTime;
  1228. begin
  1229. Result := RecodeDateTime(AValue,LFAI,LFAI,ADay,LFAI,LFAI,LFAI,LFAI);
  1230. end;
  1231. Function RecodeHour(const AValue: TDateTime; const AHour: Word): TDateTime;
  1232. begin
  1233. Result := RecodeDateTime(AValue,LFAI,LFAI,LFAI,AHour,LFAI,LFAI,LFAI);
  1234. end;
  1235. Function RecodeMinute(const AValue: TDateTime; const AMinute: Word): TDateTime;
  1236. begin
  1237. Result := RecodeDateTime(AValue,LFAI,LFAI,LFAI,LFAI,AMinute,LFAI,LFAI);
  1238. end;
  1239. Function RecodeSecond(const AValue: TDateTime; const ASecond: Word): TDateTime;
  1240. begin
  1241. Result := RecodeDateTime(AValue,LFAI,LFAI,LFAI,LFAI,LFAI,ASecond,LFAI);
  1242. end;
  1243. Function RecodeMilliSecond(const AValue: TDateTime; const AMilliSecond: Word): TDateTime;
  1244. begin
  1245. Result := RecodeDateTime(AValue,LFAI,LFAI,LFAI,LFAI,LFAI,LFAI,AMilliSecond);
  1246. end;
  1247. Function RecodeDate(const AValue: TDateTime; const AYear, AMonth, ADay: Word): TDateTime;
  1248. begin
  1249. Result := RecodeDateTime(AValue,AYear,AMonth,ADay,LFAI,LFAI,LFAI,LFAI);
  1250. end;
  1251. Function RecodeTime(const AValue: TDateTime; const AHour, AMinute, ASecond, AMilliSecond: Word): TDateTime;
  1252. begin
  1253. Result := RecodeDateTime(AValue,LFAI,LFAI,LFAI,AHour,AMinute,ASecond,AMilliSecond);
  1254. end;
  1255. Function RecodeDateTime(const AValue: TDateTime; const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word): TDateTime;
  1256. begin
  1257. If Not TryRecodeDateTime(AValue,AYear,AMonth,ADay,AHour,AMinute,ASecond,AMilliSecond,Result) then
  1258. InvalidDateTimeError(AYear,AMonth,ADay,AHour,AMinute,ASecond,AMilliSecond,AValue);
  1259. end;
  1260. Function TryRecodeDateTime(const AValue: TDateTime; const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; out AResult: TDateTime): Boolean;
  1261. Procedure FV (Var AV : Word; Arg : Word);
  1262. begin
  1263. If (Arg<>LFAI) then
  1264. AV:=Arg;
  1265. end;
  1266. Var
  1267. Y,M,D,H,N,S,MS : Word;
  1268. begin
  1269. DecodeDateTime(AValue,Y,M,D,H,N,S,MS);
  1270. FV(Y,AYear);
  1271. FV(M,AMonth);
  1272. FV(D,ADay);
  1273. FV(H,AHour);
  1274. FV(N,AMinute);
  1275. FV(S,ASecond);
  1276. FV(MS,AMillisecond);
  1277. Result:=TryEncodeDateTime(Y,M,D,H,N,S,MS,AResult);
  1278. end;
  1279. { ---------------------------------------------------------------------
  1280. Comparision of date/time
  1281. ---------------------------------------------------------------------}
  1282. Function CompareDateTime(const A, B: TDateTime): TValueRelationship;
  1283. begin
  1284. If SameDateTime(A,B) then
  1285. Result:=EqualsValue
  1286. else If A>B then
  1287. Result:=GreaterThanValue
  1288. else
  1289. Result:=LessThanValue
  1290. end;
  1291. Function CompareDate(const A, B: TDateTime): TValueRelationship;
  1292. begin
  1293. If SameDate(A,B) then
  1294. Result:=EQualsValue
  1295. else if A<B then
  1296. Result:=LessThanValue
  1297. else
  1298. Result:=GreaterThanValue;
  1299. end;
  1300. Function CompareTime(const A, B: TDateTime): TValueRelationship;
  1301. begin
  1302. If SameTime(A,B) then
  1303. Result:=EQualsValue
  1304. else If Frac(A)<Frac(B) then
  1305. Result:=LessThanValue
  1306. else
  1307. Result:=GreaterThanValue;
  1308. end;
  1309. Function SameDateTime(const A, B: TDateTime): Boolean;
  1310. begin
  1311. Result:=Abs(A-B)<OneMilliSecond;
  1312. end;
  1313. Function SameDate(const A, B: TDateTime): Boolean; inline;
  1314. begin
  1315. Result:=Trunc(A)=Trunc(B);
  1316. end;
  1317. Function SameTime(const A, B: TDateTime): Boolean;
  1318. begin
  1319. Result:=Frac(Abs(A-B))<OneMilliSecond;
  1320. end;
  1321. Function InternalNthDayOfWeek(DoM : Word) : Word;
  1322. begin
  1323. Result:=(Dom-1) div 7 +1;
  1324. end;
  1325. Function NthDayOfWeek(const AValue: TDateTime): Word;
  1326. begin
  1327. Result:=InternalNthDayOfWeek(DayOfTheMonth(AValue));
  1328. end;
  1329. Procedure DecodeDayOfWeekInMonth(const AValue: TDateTime; out AYear, AMonth, ANthDayOfWeek, ADayOfWeek: Word);
  1330. var
  1331. D: Word;
  1332. begin
  1333. DecodeDate(AValue,AYear,AMonth,D);
  1334. ADayOfWeek:=DayOfTheWeek(AValue);
  1335. ANthDayOfWeek:=InternalNthDayOfWeek(D);
  1336. end;
  1337. Function EncodeDayOfWeekInMonth(const AYear, AMonth, ANthDayOfWeek, ADayOfWeek: Word): TDateTime;
  1338. begin
  1339. If Not TryEncodeDayOfWeekInMonth(AYear,AMonth,ANthDayOfWeek,ADayOfWeek,Result) then
  1340. InvalidDayOfWeekInMonthError(AYear,AMonth,ANthDayOfWeek,ADayOfWeek);
  1341. end;
  1342. Function TryEncodeDayOfWeekInMonth(const AYear, AMonth, ANthDayOfWeek, ADayOfWeek: Word; out AValue: TDateTime): Boolean;
  1343. Var
  1344. SOM,D : Word;
  1345. begin
  1346. SOM:=DayOfTheWeek(EncodeDate(Ayear,AMonth,1));
  1347. D:=1+ADayOfWeek-SOM+7*(ANthDayOfWeek-1);
  1348. If SOM>ADayOfWeek then
  1349. D:=D+7; // Clearer would have been Inc(ANthDayOfweek) but it's a const
  1350. Result:=TryEncodeDate(Ayear,AMonth,D,AValue);
  1351. end;
  1352. { ---------------------------------------------------------------------
  1353. Exception throwing routines
  1354. ---------------------------------------------------------------------}
  1355. Procedure InvalidDateTimeError(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; const ABaseDate: TDateTime);
  1356. Function DoField(Arg,Def : Word; Unknown: String) : String;
  1357. begin
  1358. If (Arg<>LFAI) then
  1359. Result:=Format('%.*d',[Length(Unknown),Arg])
  1360. else if (ABaseDate=0) then
  1361. Result:=Unknown
  1362. else
  1363. Result:=Format('%.*d',[Length(Unknown),Arg]);
  1364. end;
  1365. Var
  1366. Y,M,D,H,N,S,MS : Word;
  1367. Msg : String;
  1368. begin
  1369. DecodeDateTime(ABasedate,Y,M,D,H,N,S,MS);
  1370. Msg:=DoField(AYear,Y,'????');
  1371. Msg:=Msg+DefaultFormatSettings.DateSeparator+DoField(AMonth,M,'??');
  1372. Msg:=Msg+DefaultFormatSettings.DateSeparator+DoField(ADay,D,'??');
  1373. Msg:=Msg+' '+DoField(AHour,H,'??');
  1374. Msg:=Msg+DefaultFormatSettings.TimeSeparator+DoField(AMinute,N,'??');
  1375. Msg:=Msg+DefaultFormatSettings.TimeSeparator+Dofield(ASecond,S,'??');
  1376. Msg:=Msg+DefaultFormatSettings.DecimalSeparator+DoField(AMilliSecond,MS,'???');
  1377. Raise EConvertError.CreateFmt(SErrInvalidTimeStamp,[Msg]);
  1378. end;
  1379. Procedure InvalidDateTimeError(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word); // const ABaseDate: TDateTime = 0
  1380. begin
  1381. InvalidDateTimeError(AYear,AMonth,ADay,AHour,AMinute,ASecond,AMilliSecond,0);
  1382. end;
  1383. Procedure InvalidDateWeekError(const AYear, AWeekOfYear, ADayOfWeek: Word);
  1384. begin
  1385. Raise EConvertError.CreateFmt(SErrInvalidDateWeek,[AYear,AWeekOfYear,ADayOfWeek]);
  1386. end;
  1387. Procedure InvalidDateDayError(const AYear, ADayOfYear: Word);
  1388. begin
  1389. Raise EConvertError.CreateFmt(SErrInvalidDayOfYear,[AYear,ADayOfYear]);
  1390. end;
  1391. Procedure InvalidDateMonthWeekError(const AYear, AMonth, AWeekOfMonth, ADayOfWeek: Word);
  1392. begin
  1393. Raise EConvertError.CreateFmt(SErrInvalidDateMonthWeek,[Ayear,AMonth,AWeekOfMonth,ADayOfWeek]);
  1394. end;
  1395. Procedure InvalidDayOfWeekInMonthError(const AYear, AMonth, ANthDayOfWeek, ADayOfWeek: Word);
  1396. begin
  1397. Raise EConvertError.CreateFmt(SErrInvalidDayOfWeekInMonth,[AYear,AMonth,ANthDayOfWeek,ADayOfWeek]);
  1398. end;
  1399. { ---------------------------------------------------------------------
  1400. Julian and Modified Julian Date conversion support
  1401. ---------------------------------------------------------------------}
  1402. {$ifopt R+}
  1403. {$define RangeCheckWasOn}
  1404. {$R-}
  1405. {$endif opt R+}
  1406. {$ifopt Q+}
  1407. {$define OverflowCheckWasOn}
  1408. {$Q-}
  1409. {$endif opt Q+}
  1410. Function DateTimeToJulianDate(const AValue: TDateTime): Double;
  1411. var
  1412. day,month,year: word;
  1413. a,y,m: integer;
  1414. begin
  1415. DecodeDate ( AValue, year, month, day );
  1416. a := (14-month) div 12;
  1417. y := year + 4800 - a;
  1418. m := month + (12*a) - 3;
  1419. result := day + ((153*m+2) div 5) + (365*y) + (y div 4) - (y div 100) + (y div 400) - 32045;
  1420. result := result - 0.5;
  1421. end;
  1422. Function JulianDateToDateTime(const AValue: Double): TDateTime;
  1423. begin
  1424. if not TryJulianDateToDateTime(AValue, Result) then
  1425. raise EConvertError.CreateFmt(SInvalidJulianDate, [AValue]);
  1426. end;
  1427. Function TryJulianDateToDateTime(const AValue: Double; out ADateTime: TDateTime): Boolean;
  1428. var
  1429. a,b,c,d,e,m:integer;
  1430. day,month,year: word;
  1431. begin
  1432. a := trunc(AValue + 32044.5);
  1433. b := (4*a + 3) div 146097;
  1434. c := a - (146097*b div 4);
  1435. d := (4*c + 3) div 1461;
  1436. e := c - (1461*d div 4);
  1437. m := (5*e+2) div 153;
  1438. day := e - ((153*m + 2) div 5) + 1;
  1439. month := m + 3 - 12 * ( m div 10 );
  1440. year := (100*b) + d - 4800 + ( m div 10 );
  1441. result := TryEncodeDate ( Year, Month, Day, ADateTime );
  1442. end;
  1443. Function DateTimeToModifiedJulianDate(const AValue: TDateTime): Double;
  1444. begin
  1445. result := DateTimeToJulianDate(AValue) - 2400000.5;
  1446. end;
  1447. Function ModifiedJulianDateToDateTime(const AValue: Double): TDateTime;
  1448. begin
  1449. result := JulianDateToDateTime(AValue + 2400000.5);
  1450. end;
  1451. Function TryModifiedJulianDateToDateTime(const AValue: Double; out ADateTime: TDateTime): Boolean;
  1452. begin
  1453. Result:=TryJulianDateToDateTime(AValue + 2400000.5, ADateTime);
  1454. end;
  1455. {$ifdef RangeCheckWasOn}
  1456. {$R+}
  1457. {$undef RangeCheckWasOn}
  1458. {$endif}
  1459. {$ifdef OverflowCheckWasOn}
  1460. {$Q+}
  1461. {$undef OverflowCheckWasOn}
  1462. {$endif}
  1463. { ---------------------------------------------------------------------
  1464. Unix timestamp support.
  1465. ---------------------------------------------------------------------}
  1466. Function DateTimeToUnix(const AValue: TDateTime): Int64;
  1467. begin
  1468. Result:=Round(DateTimeDiff(AValue,UnixEpoch)*SecsPerDay);
  1469. end;
  1470. Function UnixToDateTime(const AValue: Int64): TDateTime;
  1471. begin
  1472. Result:=IncSecond(UnixEpoch, AValue);
  1473. end;
  1474. Function UnixTimeStampToMac(const AValue: Int64): Int64;
  1475. const
  1476. Epoch=24107 * 24 * 3600;
  1477. begin
  1478. Result:=AValue + Epoch;
  1479. end;
  1480. { ---------------------------------------------------------------------
  1481. Mac timestamp support.
  1482. ---------------------------------------------------------------------}
  1483. Function DateTimeToMac(const AValue: TDateTime): Int64;
  1484. var
  1485. Epoch:TDateTime;
  1486. begin
  1487. Epoch:=EncodeDateTime( 1904, 1, 1, 0, 0, 0, 0 );
  1488. Result:=SecondsBetween( Epoch, AValue );
  1489. end;
  1490. Function MacToDateTime(const AValue: Int64): TDateTime;
  1491. var
  1492. Epoch:TDateTime;
  1493. begin
  1494. Epoch:=EncodeDateTime( 1904, 1, 1, 0, 0, 0, 0 );
  1495. Result:=IncSecond( Epoch, AValue );
  1496. end;
  1497. Function MacTimeStampToUnix(const AValue: Int64): Int64;
  1498. const
  1499. Epoch=24107 * 24 * 3600;
  1500. begin
  1501. Result:=AValue - Epoch;
  1502. end;
  1503. Function DateTimeToDosDateTime(const AValue: TDateTime): longint;
  1504. var year,month,day,hour,min,sec,msec : word;
  1505. zs : longint;
  1506. begin
  1507. decodedatetime(avalue,year,month,day,hour,min,sec,msec);
  1508. result:=-1980;
  1509. result:=result+year and 127;
  1510. result:=result shl 4;
  1511. result:=result+month;
  1512. result:=result shl 5;
  1513. result:=result+day;
  1514. result:=result shl 16;
  1515. zs:=hour;
  1516. zs:=zs shl 6;
  1517. zs:=zs+min;
  1518. zs:=zs shl 5;
  1519. zs:=zs+sec div 2;
  1520. result:=result+(zs and $ffff);
  1521. end;
  1522. Function DosDateTimeToDateTime( AValue: longint): TDateTime;
  1523. var year,month,day,hour,min,sec : integer;
  1524. begin
  1525. sec:=(AValue and 31) * 2;
  1526. avalue:=AValue shr 5;
  1527. min:=AValue and 63;
  1528. avalue:=AValue shr 6;
  1529. hour:=AValue and 31;
  1530. avalue:=AValue shr 5;
  1531. day:=AValue and 31;
  1532. avalue:=AValue shr 5;
  1533. month:=AValue and 15;
  1534. avalue:=AValue shr 4;
  1535. year:=AValue+1980;
  1536. result:=EncodeDateTime(year,month,day,hour,min,sec,0);
  1537. end;
  1538. {
  1539. Inverse of formatdatetime, destined for the dateutils unit of FPC.
  1540. Limitations/implementation details:
  1541. - An inverse of FormatDateTime is not 100% an inverse, simply because one can put e.g. time tokens twice in the format string,
  1542. and scandatetime wouldn't know which time to pick.
  1543. - Strings like hn can't be reversed safely. E.g. 1:2 (2 minutes after 1) delivers 12 which is parsed as 12:00 and then
  1544. misses chars for the "n" part.
  1545. - trailing characters are ignored.
  1546. - no support for Eastern Asian formatting characters since they are windows only.
  1547. - no MBCS support.
  1548. Extensions
  1549. - #9 eats whitespace.
  1550. - whitespace at the end of a pattern is optional.
  1551. - ? matches any char.
  1552. - Quote the above chars to really match the char.
  1553. }
  1554. const whitespace = [' ',#13,#10];
  1555. hrfactor = 1/(24);
  1556. minfactor = 1/(24*60);
  1557. secfactor = 1/(24*60*60);
  1558. mssecfactor = 1/(24*60*60*1000);
  1559. const AMPMformatting : array[0..2] of string =('am/pm','a/p','ampm');
  1560. procedure raiseexception(const s:string);
  1561. begin
  1562. raise EConvertError.Create(s);
  1563. end;
  1564. function scandatetime(const pattern:string;const s:string;const fmt:TFormatSettings;startpos:integer=1) : tdatetime;
  1565. var len ,ind : integer;
  1566. yy,mm,dd : integer;
  1567. timeval : TDateTime;
  1568. activequote: char;
  1569. procedure intscandate(ptrn:pchar;plen:integer;poffs:integer);
  1570. // poffs is the offset to
  1571. var
  1572. pind : integer;
  1573. function findimatch(const mnts:array of string;p:pchar):integer;
  1574. var i : integer;
  1575. begin
  1576. result:=-1;
  1577. i:=0;
  1578. while (i<=high(mnts)) and (result=-1) do
  1579. begin
  1580. if AnsiStrLIComp(p,@mnts[i][1],length(mnts[i]))=0 then
  1581. result:=i;
  1582. inc(i);
  1583. end;
  1584. end;
  1585. procedure arraymatcherror;
  1586. begin
  1587. raiseexception(format(SNoArrayMatch,[pind+1,ind]))
  1588. end;
  1589. function findmatch(const mnts : array of string;const s:string):integer;
  1590. begin
  1591. result:=findimatch(mnts,@s[ind]);
  1592. if result=-1 then
  1593. arraymatcherror
  1594. else
  1595. begin
  1596. inc(ind,length(mnts[result])+1);
  1597. inc(pind,length(mnts[result])+1);
  1598. inc(result); // was 0 based.
  1599. end;
  1600. end;
  1601. var
  1602. pivot,
  1603. i : integer;
  1604. function scanfixedint(maxv:integer):integer;
  1605. var c : char;
  1606. oi:integer;
  1607. begin
  1608. result:=0;
  1609. oi:=ind;
  1610. c:=ptrn[pind];
  1611. while (pind<plen) and (ptrn[pind]=c) do inc(pind);
  1612. while (maxv>0) and (ind<=len) and (s[ind] IN ['0'..'9']) do
  1613. begin
  1614. result:=result*10+ord(s[ind])-48;
  1615. inc(ind);
  1616. dec(maxv);
  1617. end;
  1618. if oi=ind then
  1619. raiseexception(format(SPatternCharMismatch,[c,oi]));
  1620. end;
  1621. procedure matchchar(c:char);
  1622. begin
  1623. if (ind>len) or (s[ind]<>c) then
  1624. raiseexception(format(SNoCharMatch,[s[ind],c,pind+poffs+1,ind]));
  1625. inc(pind);
  1626. inc(ind);
  1627. end;
  1628. function scanpatlen:integer;
  1629. var c : char;
  1630. lind : Integer;
  1631. begin
  1632. result:=pind;
  1633. lind:=pind;
  1634. c:=ptrn[lind];
  1635. while (lind<=plen) and (ptrn[lind]=c) do
  1636. inc(lind);
  1637. result:=lind-result;
  1638. end;
  1639. procedure matchpattern(const lptr:string);
  1640. var len:integer;
  1641. begin
  1642. len:=length(lptr);
  1643. if len>0 then
  1644. intscandate(@lptr[1],len,pind+poffs);
  1645. end;
  1646. var lasttoken,lch : char;
  1647. begin
  1648. pind:=0; lasttoken:=' ';
  1649. while (ind<=len) and (pind<plen) do
  1650. begin
  1651. lch:=upcase(ptrn[pind]);
  1652. if activequote=#0 then
  1653. begin
  1654. if (lch='M') and (lasttoken='H') then
  1655. begin
  1656. i:=scanpatlen;
  1657. if i>2 then
  1658. raiseexception(format(Shhmmerror,[poffs+pind+1]));
  1659. timeval:=timeval+scanfixedint(2)* minfactor;
  1660. end
  1661. else
  1662. case lch of
  1663. 'H': timeval:=timeval+scanfixedint(2)* hrfactor;
  1664. 'D': begin
  1665. i:=scanpatlen;
  1666. case i of
  1667. 1,2 : dd:=scanfixedint(2);
  1668. 3 : dd:=findmatch(fmt.shortDayNames,s);
  1669. 4 : dd:=findmatch(fmt.longDayNames,s);
  1670. 5 : matchpattern(fmt.shortdateformat);
  1671. 6 : matchpattern(fmt.longdateformat);
  1672. end;
  1673. end;
  1674. 'N': timeval:=timeval+scanfixedint(2)* minfactor;
  1675. 'S': timeval:=timeval+scanfixedint(2)* secfactor;
  1676. 'Z': timeval:=timeval+scanfixedint(3)* mssecfactor;
  1677. 'Y': begin
  1678. i:=scanpatlen;
  1679. yy:=scanfixedint(i);
  1680. if i<=2 then
  1681. begin
  1682. pivot:=YearOf(now)-fmt.TwoDigitYearCenturyWindow;
  1683. inc(yy, pivot div 100 * 100);
  1684. if (fmt.TwoDigitYearCenturyWindow > 0) and (yy < pivot) then
  1685. inc(yy, 100);
  1686. end;
  1687. end;
  1688. 'M': begin
  1689. i:=scanpatlen;
  1690. case i of
  1691. 1,2: mm:=scanfixedint(2);
  1692. 3: mm:=findmatch(fmt.ShortMonthNames,s);
  1693. 4: mm:=findmatch(fmt.LongMonthNames,s);
  1694. end;
  1695. end;
  1696. 'T' : begin
  1697. i:=scanpatlen;
  1698. case i of
  1699. 1: matchpattern(fmt.shortdateformat);
  1700. 2: matchpattern(fmt.longtimeformat);
  1701. end;
  1702. end;
  1703. 'A' : begin
  1704. i:=findimatch(AMPMformatting,@ptrn[pind]);
  1705. case i of
  1706. 0: begin
  1707. i:=findimatch(['AM','PM'],@s[ind]);
  1708. case i of
  1709. 0: ;
  1710. 1: timeval:=timeval+12*hrfactor;
  1711. else
  1712. arraymatcherror
  1713. end;
  1714. inc(pind,length(AMPMformatting[0]));
  1715. inc(ind,2);
  1716. end;
  1717. 1: begin
  1718. case upcase(s[ind]) of
  1719. 'A' : ;
  1720. 'P' : timeval:=timeval+12*hrfactor;
  1721. else
  1722. arraymatcherror
  1723. end;
  1724. inc(pind,length(AMPMformatting[1]));
  1725. inc(ind);
  1726. end;
  1727. 2: begin
  1728. i:=findimatch([fmt.timeamstring,fmt.timepmstring],@s[ind]);
  1729. case i of
  1730. 0: inc(ind,length(fmt.timeamstring));
  1731. 1: begin
  1732. timeval:=timeval+12*hrfactor;
  1733. inc(ind,length(fmt.timepmstring));
  1734. end;
  1735. else
  1736. arraymatcherror
  1737. end;
  1738. inc(pind,length(AMPMformatting[2]));
  1739. inc(pind,2);
  1740. inc(ind,2);
  1741. end;
  1742. else // no AM/PM match. Assume 'a' is simply a char
  1743. matchchar(ptrn[pind]);
  1744. end;
  1745. end;
  1746. '/' : matchchar(fmt.dateSeparator);
  1747. ':' : begin
  1748. matchchar(fmt.TimeSeparator);
  1749. lch:=lasttoken;
  1750. end;
  1751. #39,'"' : begin
  1752. activequote:=lch;
  1753. inc(pind);
  1754. end;
  1755. 'C' : begin
  1756. intscandate(@fmt.shortdateformat[1],length(fmt.ShortDateFormat),pind+poffs);
  1757. intscandate(@fmt.longtimeformat[1],length(fmt.longtimeformat),pind+poffs);
  1758. inc(pind);
  1759. end;
  1760. '?' : begin
  1761. inc(pind);
  1762. inc(ind);
  1763. end;
  1764. #9 : begin
  1765. while (ind<=len) and (s[ind] in whitespace) do
  1766. inc(ind);
  1767. inc(pind);
  1768. end;
  1769. else
  1770. matchchar(ptrn[pind]);
  1771. end; {case}
  1772. lasttoken:=lch;
  1773. end
  1774. else
  1775. begin
  1776. if activequote=lch then
  1777. begin
  1778. activequote:=#0;
  1779. inc(pind);
  1780. end
  1781. else
  1782. matchchar(ptrn[pind]);
  1783. end;
  1784. end;
  1785. if (pind<plen) and (plen>0) and (ptrn[plen-1]<>#9) then // allow omission of trailing whitespace
  1786. RaiseException(format(SFullpattern,[poffs+pind+1]));
  1787. end;
  1788. var plen:integer;
  1789. begin
  1790. activequote:=#0;
  1791. yy:=0; mm:=0; dd:=0;
  1792. timeval:=0.0;
  1793. len:=length(s); ind:=startpos;
  1794. plen:=length(pattern);
  1795. intscandate(@pattern[1],plen,0);
  1796. result:=timeval;
  1797. if (yy>0) and (mm>0) and (dd>0) then
  1798. result:=result+encodedate(yy,mm,dd);
  1799. end;
  1800. function scandatetime(const pattern:string;const s:string;startpos:integer=1) : tdatetime; overload;
  1801. begin
  1802. result:=scandatetime(pattern,s,defaultformatsettings);
  1803. end;
  1804. {$else}
  1805. implementation
  1806. {$endif FPUNONE}
  1807. end.