dateutils.pas 77 KB

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