dateutil.inc 77 KB

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