dateutil.inc 68 KB

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