dati.inc 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619
  1. {
  2. *********************************************************************
  3. Copyright (C) 1997, 1998 Gertjan Schouten
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************
  10. System Utilities For Free Pascal
  11. }
  12. {==============================================================================}
  13. { internal functions }
  14. {==============================================================================}
  15. Function DoEncodeDate(Year, Month, Day: Word): longint;
  16. Var
  17. D : TDateTime;
  18. begin
  19. If TryEncodeDate(Year,Month,Day,D) then
  20. Result:=Trunc(D)
  21. else
  22. Result:=0;
  23. end;
  24. function DoEncodeTime(Hour, Minute, Second, MilliSecond: word): TDateTime;
  25. begin
  26. If not TryEncodeTime(Hour,Minute,Second,MilliSecond,Result) then
  27. Result:=0;
  28. end;
  29. {==============================================================================}
  30. { Public functions }
  31. {==============================================================================}
  32. { ComposeDateTime converts a Date and a Time into one TDateTime }
  33. function ComposeDateTime(Date,Time : TDateTime) : TDateTime;
  34. begin
  35. if Date < 0 then Result := trunc(Date) - Abs(frac(Time))
  36. else Result := trunc(Date) + Abs(frac(Time));
  37. end;
  38. { DateTimeToTimeStamp converts DateTime to a TTimeStamp }
  39. function DateTimeToTimeStamp(DateTime: TDateTime): TTimeStamp;
  40. Var
  41. D : Double;
  42. begin
  43. D:=DateTime * Single(MSecsPerDay);
  44. if D<0 then
  45. D:=D-0.5
  46. else
  47. D:=D+0.5;
  48. result.Time := Abs(Trunc(D)) Mod MSecsPerDay;
  49. result.Date := DateDelta + Trunc(D) div MSecsPerDay;
  50. end;
  51. { TimeStampToDateTime converts TimeStamp to a TDateTime value }
  52. function TimeStampToDateTime(const TimeStamp: TTimeStamp): TDateTime;
  53. begin
  54. Result := ComposeDateTime(TimeStamp.Date - DateDelta,TimeStamp.Time / MSecsPerDay)
  55. end;
  56. { MSecsToTimeStamp }
  57. function MSecsToTimeStamp(MSecs: comp): TTimeStamp;
  58. var
  59. D1:Int64;
  60. begin
  61. D1:=Trunc(msecs);
  62. result.Date := D1 div msecsperday;
  63. result.Time := D1 - result.date * msecsperday;
  64. end;
  65. { TimeStampToMSecs }
  66. function TimeStampToMSecs(const TimeStamp: TTimeStamp): comp;
  67. begin
  68. result := TimeStamp.Time + comp(timestamp.date)*msecsperday;
  69. end;
  70. Function TryEncodeDate(Year,Month,Day : Word; Out Date : TDateTime) : Boolean;
  71. var
  72. c, ya: cardinal;
  73. begin
  74. Result:=(Year>0) and (Year<10000) and
  75. (Month in [1..12]) and
  76. (Day>0) and (Day<=MonthDays[IsleapYear(Year),Month]);
  77. If Result then
  78. begin
  79. if month > 2 then
  80. Dec(Month,3)
  81. else
  82. begin
  83. Inc(Month,9);
  84. Dec(Year);
  85. end;
  86. c:= Year DIV 100;
  87. ya:= Year - 100*c;
  88. Date := (146097*c) SHR 2 + (1461*ya) SHR 2 + (153*cardinal(Month)+2) DIV 5 + cardinal(Day);
  89. // Note that this line can't be part of the line above, since TDateTime is
  90. // signed and c and ya are not
  91. Date := Date - 693900;
  92. end
  93. end;
  94. function TryEncodeTime(Hour, Min, Sec, MSec:word; Out Time : TDateTime) : boolean;
  95. begin
  96. Result:=((Hour<24) and (Min<60) and (Sec<60) and (MSec<1000)) or
  97. { allow leap second }
  98. ((Hour=23) and (Min=59) and (Sec=60) and (MSec<1000));
  99. If Result then
  100. Time:=TDateTime(cardinal(Hour)*3600000+cardinal(Min)*60000+cardinal(Sec)*1000+MSec)/MSecsPerDay;
  101. end;
  102. { EncodeDate packs three variables Year, Month and Day into a
  103. TDateTime value the result is the number of days since 12/30/1899 }
  104. function EncodeDate(Year, Month, Day: word): TDateTime;
  105. begin
  106. If Not TryEncodeDate(Year,Month,Day,Result) then
  107. Raise EConvertError.CreateFmt('%d-%d-%d is not a valid date specification',
  108. [Year,Month,Day]);
  109. end;
  110. { EncodeTime packs four variables Hour, Minute, Second and MilliSecond into
  111. a TDateTime value }
  112. function EncodeTime(Hour, Minute, Second, MilliSecond:word):TDateTime;
  113. begin
  114. If not TryEncodeTime(Hour,Minute,Second,MilliSecond,Result) then
  115. Raise EConvertError.CreateFmt('%d:%d:%d.%d is not a valid time specification',
  116. [Hour,Minute,Second,MilliSecond]);
  117. end;
  118. { DecodeDate unpacks the value Date into three values:
  119. Year, Month and Day }
  120. procedure DecodeDate(Date: TDateTime; out Year, Month, Day: word);
  121. var
  122. ly,ld,lm,j : cardinal;
  123. begin
  124. if Date <= -datedelta then // If Date is before 1-1-1 then return 0-0-0
  125. begin
  126. Year := 0;
  127. Month := 0;
  128. Day := 0;
  129. end
  130. else
  131. begin
  132. if Date>0 then
  133. Date:=Date+1/(msecsperday*2)
  134. else
  135. Date:=Date-1/(msecsperday*2);
  136. if Date>MaxDateTime then
  137. Date:=MaxDateTime;
  138. // Raise EConvertError.CreateFmt('%f is not a valid TDatetime encoding, maximum value is %f.',[Date,MaxDateTime]);
  139. j := pred((longint(Trunc(System.Int(Date))) + 693900) SHL 2);
  140. ly:= j DIV 146097;
  141. j:= j - 146097 * cardinal(ly);
  142. ld := j SHR 2;
  143. j:=(ld SHL 2 + 3) DIV 1461;
  144. ld:= (cardinal(ld) SHL 2 + 7 - 1461*j) SHR 2;
  145. lm:=(5 * ld-3) DIV 153;
  146. ld:= (5 * ld +2 - 153*lm) DIV 5;
  147. ly:= 100 * cardinal(ly) + j;
  148. if lm < 10 then
  149. inc(lm,3)
  150. else
  151. begin
  152. dec(lm,9);
  153. inc(ly);
  154. end;
  155. year:=ly;
  156. month:=lm;
  157. day:=ld;
  158. end;
  159. end;
  160. function DecodeDateFully(const DateTime: TDateTime; out Year, Month, Day, DOW: Word): Boolean;
  161. begin
  162. DecodeDate(DateTime,Year,Month,Day);
  163. DOW:=DayOfWeek(DateTime);
  164. Result:=IsLeapYear(Year);
  165. end;
  166. { DecodeTime unpacks Time into four values:
  167. Hour, Minute, Second and MilliSecond }
  168. procedure DecodeTime(Time: TDateTime; out Hour, Minute, Second, MilliSecond: word);
  169. Var
  170. l : cardinal;
  171. begin
  172. l := DateTimeToTimeStamp(Time).Time;
  173. Hour := l div 3600000;
  174. l := l mod 3600000;
  175. Minute := l div 60000;
  176. l := l mod 60000;
  177. Second := l div 1000;
  178. l := l mod 1000;
  179. MilliSecond := l;
  180. end;
  181. { DateTimeToSystemTime converts DateTime value to SystemTime }
  182. procedure DateTimeToSystemTime(DateTime: TDateTime; out SystemTime: TSystemTime);
  183. begin
  184. DecodeDateFully(DateTime, SystemTime.Year, SystemTime.Month, SystemTime.Day,SystemTime.DayOfWeek);
  185. DecodeTime(DateTime, SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond);
  186. Dec(SystemTime.DayOfWeek);
  187. end ;
  188. { SystemTimeToDateTime converts SystemTime to a TDateTime value }
  189. function SystemTimeToDateTime(const SystemTime: TSystemTime): TDateTime;
  190. begin
  191. result := ComposeDateTime(DoEncodeDate(SystemTime.Year, SystemTime.Month, SystemTime.Day),
  192. DoEncodeTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond));
  193. end ;
  194. { DayOfWeek returns the Day of the week (sunday is day 1) }
  195. function DayOfWeek(DateTime: TDateTime): integer;
  196. begin
  197. Result := 1 + ((Trunc(DateTime) - 1) mod 7);
  198. If (Result<=0) then
  199. Inc(Result,7);
  200. end;
  201. { Date returns the current Date }
  202. function Date: TDateTime;
  203. var
  204. SystemTime: TSystemTime;
  205. begin
  206. GetLocalTime(SystemTime);
  207. result := DoEncodeDate(SystemTime.Year, SystemTime.Month, SystemTime.Day);
  208. end ;
  209. { Time returns the current Time }
  210. function Time: TDateTime;
  211. var
  212. SystemTime: TSystemTime;
  213. begin
  214. GetLocalTime(SystemTime);
  215. Result := DoEncodeTime(SystemTime.Hour,SystemTime.Minute,SystemTime.Second,SystemTime.MilliSecond);
  216. end ;
  217. { Now returns the current Date and Time }
  218. function Now: TDateTime;
  219. var
  220. SystemTime: TSystemTime;
  221. begin
  222. GetLocalTime(SystemTime);
  223. result := systemTimeToDateTime(SystemTime);
  224. end;
  225. { NowUTC returns the current UTC Date and Time if available on the OS. If not, local date is returned }
  226. function NowUTC: TDateTime;
  227. var
  228. SystemTime: TSystemTime;
  229. begin
  230. if not GetUniversalTime(SystemTime) then
  231. GetLocalTime(SystemTime);
  232. result := systemTimeToDateTime(SystemTime);
  233. end;
  234. { IncMonth increments DateTime with NumberOfMonths months,
  235. NumberOfMonths can be less than zero }
  236. function IncMonth(const DateTime: TDateTime; NumberOfMonths: integer = 1 ): TDateTime;
  237. var
  238. Year, Month, Day : word;
  239. begin
  240. DecodeDate(DateTime, Year, Month, Day);
  241. IncAMonth(Year, Month, Day, NumberOfMonths);
  242. result := ComposeDateTime(DoEncodeDate(Year, Month, Day), DateTime);
  243. end ;
  244. { IncAMonth is the same as IncMonth, but operates on decoded date }
  245. procedure IncAMonth(var Year, Month, Day: Word; NumberOfMonths: Integer = 1);
  246. var
  247. TempMonth, S: Integer;
  248. begin
  249. If NumberOfMonths>=0 then
  250. s:=1
  251. else
  252. s:=-1;
  253. inc(Year,(NumberOfMonths div 12));
  254. TempMonth:=Month+(NumberOfMonths mod 12)-1;
  255. if (TempMonth>11) or
  256. (TempMonth<0) then
  257. begin
  258. Dec(TempMonth, S*12);
  259. Inc(Year, S);
  260. end;
  261. Month:=TempMonth+1; { Months from 1 to 12 }
  262. If (Day>MonthDays[IsLeapYear(Year)][Month]) then
  263. Day:=MonthDays[IsLeapYear(Year)][Month];
  264. end;
  265. { IsLeapYear returns true if Year is a leap year }
  266. function IsLeapYear(Year: Word): boolean;
  267. begin
  268. Result := (Year mod 4 = 0) and ((Year mod 100 <> 0) or (Year mod 400 = 0));
  269. end;
  270. { DateToStr returns a string representation of Date using ShortDateFormat }
  271. function DateToStr(Date: TDateTime): string;
  272. begin
  273. DateTimeToString(Result, 'ddddd', Date);
  274. end ;
  275. function DateToStr(Date: TDateTime; const FormatSettings: TFormatSettings): string;
  276. begin
  277. DateTimeToString(result, FormatSettings.ShortDateFormat, Date, FormatSettings);
  278. end;
  279. { TimeToStr returns a string representation of Time using LongTimeFormat }
  280. function TimeToStr(Time: TDateTime): string;
  281. begin
  282. DateTimeToString(Result, 'tt', Time);
  283. end ;
  284. function TimeToStr(Time: TDateTime; const FormatSettings: TFormatSettings): string;
  285. begin
  286. DateTimeToString(Result, FormatSettings.LongTimeFormat, Time, FormatSettings);
  287. end;
  288. { DateTimeToStr returns a string representation of DateTime using ShortDateFormat and LongTimeFormat }
  289. Const
  290. DateTimeToStrFormat : Array[Boolean] of string = ('c','f');
  291. function DateTimeToStr(DateTime: TDateTime; ForceTimeIfZero : Boolean = False): string;
  292. begin
  293. DateTimeToString(Result, DateTimeToStrFormat[ForceTimeIfZero], DateTime)
  294. end ;
  295. function DateTimeToStr(DateTime: TDateTime; const FormatSettings: TFormatSettings; ForceTimeIfZero : Boolean = False): string;
  296. begin
  297. DateTimeToString(Result, DateTimeToStrFormat[ForceTimeIfZero], DateTime ,FormatSettings);
  298. end;
  299. { StrToDate converts the string S to a TDateTime value
  300. if S does not represent a valid date value
  301. an EConvertError will be raised }
  302. function IntStrToDate(Out ErrorMsg : AnsiString; const S: PChar; Len : integer; const useformat : string; const defs:TFormatSettings; separator : char = #0): TDateTime;
  303. const SInvalidDateFormat = '"%s" is not a valid date format';
  304. procedure FixErrorMsg(const errm :ansistring;const errmarg : ansistring);
  305. begin
  306. errormsg:=format(errm,[errmarg]);
  307. end;
  308. var
  309. df:string;
  310. d,m,y,ly:integer;
  311. n,i:longint;
  312. c:word;
  313. dp,mp,yp,which : Byte;
  314. s1:string;
  315. values:array[0..3] of longint;
  316. LocalTime:tsystemtime;
  317. YearMoreThenTwoDigits : boolean;
  318. begin
  319. ErrorMsg:=''; Result:=0;
  320. While (Len>0) and (S[Len-1] in [' ',#8,#9,#10,#12,#13]) do
  321. Dec(len);
  322. if (Len=0) then
  323. begin
  324. FixErrorMsg(SInvalidDateFormat,'');
  325. exit;
  326. end;
  327. YearMoreThenTwoDigits := False;
  328. if separator = #0 then
  329. separator := defs.DateSeparator;
  330. df := UpperCase(useFormat);
  331. { Determine order of D,M,Y }
  332. yp:=0;
  333. mp:=0;
  334. dp:=0;
  335. Which:=0;
  336. i:=0;
  337. while (i<Length(df)) and (Which<3) do
  338. begin
  339. inc(i);
  340. Case df[i] of
  341. 'Y' :
  342. if yp=0 then
  343. begin
  344. Inc(Which);
  345. yp:=which;
  346. end;
  347. 'M' :
  348. if mp=0 then
  349. begin
  350. Inc(Which);
  351. mp:=which;
  352. end;
  353. 'D' :
  354. if dp=0 then
  355. begin
  356. Inc(Which);
  357. dp:=which;
  358. end;
  359. end;
  360. end;
  361. for i := 1 to 3 do
  362. values[i] := 0;
  363. s1 := '';
  364. n := 0;
  365. dec(len);
  366. for i := 0 to len do
  367. begin
  368. if s[i] in ['0'..'9'] then
  369. s1 := s1 + s[i];
  370. { space can be part of the shortdateformat, and is defaultly in slovak
  371. windows, therefor it shouldn't be taken as separator (unless so specified)
  372. and ignored }
  373. if (Separator <> ' ') and (s[i] = ' ') then
  374. Continue;
  375. if (s[i] = separator) or ((i = len) and (s[i] in ['0'..'9'])) then
  376. begin
  377. inc(n);
  378. if n>3 then
  379. begin
  380. FixErrorMsg(SInvalidDateFormat,s);
  381. exit;
  382. end;
  383. // Check if the year has more then two digits (if n=yp, then we are evaluating the year.)
  384. if (n=yp) and (length(s1)>2) then YearMoreThenTwoDigits := True;
  385. val(s1, values[n], c);
  386. // Writeln(s1,'->',values[n]);
  387. if c<>0 then
  388. begin
  389. FixErrorMsg(SInvalidDateFormat,s);
  390. Exit;
  391. end;
  392. s1 := '';
  393. end
  394. else if not (s[i] in ['0'..'9']) then
  395. begin
  396. FixErrorMsg(SInvalidDateFormat,s);
  397. Exit;
  398. end;
  399. end ;
  400. if (Which<3) and (N>Which) then
  401. begin
  402. FixErrorMsg(SInvalidDateFormat,s);
  403. Exit;
  404. end;
  405. // Fill in values.
  406. getLocalTime(LocalTime);
  407. ly := LocalTime.Year;
  408. for I:=1 to 3 do
  409. if values[i]>high(Word) then
  410. begin
  411. errormsg:='Invalid date';
  412. exit;
  413. end;
  414. If N=3 then
  415. begin
  416. y:=values[yp];
  417. m:=values[mp];
  418. d:=values[dp];
  419. end
  420. Else
  421. begin
  422. Y:=ly;
  423. If n<2 then
  424. begin
  425. d:=values[1];
  426. m := LocalTime.Month;
  427. end
  428. else
  429. If dp<mp then
  430. begin
  431. d:=values[1];
  432. m:=values[2];
  433. end
  434. else
  435. begin
  436. d:=values[2];
  437. m:=values[1];
  438. end;
  439. end;
  440. if (y >= 0) and (y < 100) and not YearMoreThenTwoDigits then
  441. begin
  442. ly := ly - defs.TwoDigitYearCenturyWindow;
  443. Inc(Y, ly div 100 * 100);
  444. if (defs.TwoDigitYearCenturyWindow > 0) and (Y < ly) then
  445. Inc(Y, 100);
  446. end;
  447. if not TryEncodeDate(y, m, d, result) then
  448. errormsg:='Invalid date';
  449. end;
  450. function StrToDate(const S: PChar; Len : integer; const useformat : string; separator : char = #0): TDateTime;
  451. Var
  452. MSg : AnsiString;
  453. begin
  454. Result:=IntStrToDate(Msg,S,Len,useFormat,DefaultFormatSettings,Separator);
  455. If (Msg<>'') then
  456. Raise EConvertError.Create(Msg);
  457. end;
  458. function StrToDate(const S: string; FormatSettings: TFormatSettings): TDateTime;
  459. var
  460. Msg: AnsiString;
  461. begin
  462. Result:=IntStrToDate(Msg,PChar(S),Length(S),FormatSettings.ShortDateFormat,FormatSettings);
  463. if Msg<>'' then
  464. raise EConvertError.Create(Msg);
  465. end;
  466. function StrToDate(const S: ShortString; const useformat : string; separator : char = #0): TDateTime;
  467. begin
  468. // S[1] always exists for shortstring. Length 0 will trigger an error.
  469. result := StrToDate(@S[1],Length(s),UseFormat,separator);
  470. end;
  471. function StrToDate(const S: AnsiString; const useformat : string; separator : char = #0): TDateTime;
  472. begin
  473. result := StrToDate(PChar(S),Length(s),UseFormat,separator);
  474. end;
  475. function StrToDate(const S: ShortString; separator : char): TDateTime;
  476. begin
  477. // S[1] always exists for shortstring. Length 0 will trigger an error.
  478. result := StrToDate(@S[1],Length(s),DefaultFormatSettings.ShortDateFormat,separator)
  479. end;
  480. function StrToDate(const S: ShortString): TDateTime;
  481. begin
  482. // S[1] always exists for shortstring. Length 0 will trigger an error.
  483. result := StrToDate(@S[1],Length(s),DefaultFormatSettings.ShortDateFormat,#0);
  484. end;
  485. function StrToDate(const S: AnsiString; separator : char): TDateTime;
  486. begin
  487. result := StrToDate(Pchar(S),Length(s),DefaultFormatSettings.ShortDateFormat,separator)
  488. end;
  489. function StrToDate(const S: AnsiString): TDateTime;
  490. begin
  491. result := StrToDate(Pchar(S),Length(s),DefaultFormatSettings.ShortDateFormat,#0);
  492. end;
  493. { StrToTime converts the string S to a TDateTime value
  494. if S does not represent a valid time value an
  495. EConvertError will be raised }
  496. function IntStrToTime(Out ErrorMsg : AnsiString; const S: PChar; Len : integer;const defs:TFormatSettings; separator : char = #0): TDateTime;
  497. const
  498. AMPM_None = 0;
  499. AMPM_AM = 1;
  500. AMPM_PM = 2;
  501. tiHour = 0;
  502. tiMin = 1;
  503. tiSec = 2;
  504. tiMSec = 3;
  505. type
  506. TTimeValues = array[tiHour..tiMSec] of Word;
  507. var
  508. AmPm: integer;
  509. TimeValues: TTimeValues;
  510. function StrPas(Src : PChar; len: integer = 0) : ShortString;
  511. begin
  512. //this is unsafe for len > 255, it will trash memory (I tested this)
  513. //reducing it is safe, since whenever we use this a string > 255 is invalid anyway
  514. if len > 255 then len := 255;
  515. SetLength(Result, len);
  516. move(src[0],result[1],len);
  517. end;
  518. function SplitElements(out TimeValues: TTimeValues; out AmPm: Integer): Boolean;
  519. //Strict version. It does not allow #32 as Separator, it will treat it as whitespace always
  520. const
  521. Digits = ['0'..'9'];
  522. var
  523. Cur, Offset, ElemLen, Err, TimeIndex, FirstSignificantDigit: Integer;
  524. Value: Word;
  525. DigitPending, MSecPending: Boolean;
  526. AmPmStr: ShortString;
  527. CurChar: Char;
  528. begin
  529. Result := False;
  530. AmPm := AMPM_None; //No Am or PM in string found yet
  531. MSecPending := False;
  532. TimeIndex := 0; //indicating which TTimeValue must be filled next
  533. FillChar(TimeValues, SizeOf(TTimeValues), 0);
  534. Cur := 0;
  535. //skip leading blanks
  536. While (Cur < Len) and (S[Cur] =#32) do Inc(Cur);
  537. Offset := Cur;
  538. //First non-blank cannot be Separator or DecimalSeparator
  539. if (Cur > Len - 1) or (S[Cur] = Separator) or (S[Cur] = defs.Decimalseparator) then Exit;
  540. DigitPending := (S[Cur] in Digits);
  541. While (Cur < Len) do
  542. begin
  543. //writeln;
  544. //writeln('Main While loop: Cur = ',Cur,' S[Cur] = "',S[Cur],'" Len = ',Len);
  545. CurChar := S[Cur];
  546. if CurChar in Digits then
  547. begin//Digits
  548. //HH, MM, SS, or Msec?
  549. //writeln('Digit');
  550. //Digits are only allowed after starting Am/PM or at beginning of string or after Separator
  551. //and TimeIndex must be <= tiMSec
  552. //Uncomment "or (#32 = Separator)" and it will allllow #32 as separator
  553. if (not (DigitPending {or (#32 = Separator)})) or (TimeIndex > tiMSec) then Exit;
  554. OffSet := Cur;
  555. if (CurChar <> '0') then FirstSignificantDigit := OffSet else FirstSignificantDigit := -1;
  556. while (Cur < Len -1) and (S[Cur + 1] in Digits) do
  557. begin
  558. //Mark first Digit that is not '0'
  559. if (FirstSignificantDigit = -1) and (S[Cur] <> '0') then FirstSignificantDigit := Cur;
  560. Inc(Cur);
  561. end;
  562. if (FirstSignificantDigit = -1) then FirstSignificantDigit := Cur;
  563. ElemLen := 1 + Cur - FirstSignificantDigit;
  564. //writeln(' S[FirstSignificantDigit] = ',S[FirstSignificantDigit], ' S[Cur] = ',S[Cur],' ElemLen = ',ElemLen,' -> ', StrPas(S + Offset, ElemLen));
  565. //writeln(' Cur = ',Cur);
  566. //this way we know that Val() will never overflow Value !
  567. if (ElemLen <= 2) or ((ElemLen <= 3) and (TimeIndex = tiMSec) ) then
  568. begin
  569. Val(StrPas(S + FirstSignificantDigit, ElemLen), Value, Err);
  570. //writeln(' Value = ',Value,' HH = ',TimeValues[0],' MM = ',TimeValues[1],' SS = ',TimeValues[2],' MSec = ',Timevalues[3]);
  571. //This is safe now, because we know Value < High(Word)
  572. TimeValues[TimeIndex] := Value;
  573. Inc(TimeIndex);
  574. DigitPending := False;
  575. end
  576. else Exit; //Value to big, so it must be a wrong timestring
  577. end//Digits
  578. else if (CurChar = #32) then
  579. begin
  580. //writeln('#32');
  581. //just skip, but we must adress this, or it will be parsed by either AM/PM or Separator
  582. end
  583. else if (CurChar = Separator) then
  584. begin
  585. //writeln('Separator');
  586. if DigitPending or (TimeIndex > tiSec) then Exit;
  587. DigitPending := True;
  588. MSecPending := False;
  589. end
  590. else if (CurChar = defs.DecimalSeparator) then
  591. begin
  592. //writeln('DecimalSeparator');
  593. if DigitPending or MSecPending or (TimeIndex <> tiMSec) then Exit;
  594. DigitPending := True;
  595. MSecPending := True;
  596. end
  597. else
  598. begin//AM/PM?
  599. //None of the above, so this char _must_ be the start of AM/PM string
  600. //If we already have found AM/PM or we expect a digit then then timestring must be wrong at this point
  601. //writeln('AM/PM?');
  602. if (AmPm <> AMPM_None) or DigitPending then Exit;
  603. OffSet := Cur;
  604. while (Cur < Len -1) and (not (S[Cur + 1] in [Separator, #32, defs.DecimalSeparator]))
  605. and not (S[Cur + 1] in Digits) do Inc(Cur);
  606. ElemLen := 1 + Cur - OffSet;
  607. //writeln(' S[Offset] = ',S[Offset], ' S[Cur] = ',S[Cur],' ElemLen = ',ElemLen,' -> ', StrPas(S + Offset, ElemLen));
  608. //writeln(' Cur = ',Cur);
  609. AmPmStr := StrPas(S + OffSet, ElemLen);
  610. //writeln('AmPmStr = ',ampmstr,' (',length(ampmstr),')');
  611. //We must compare to TimeAMString before hardcoded 'AM' for delphi compatibility
  612. //Also it is perfectly legal, though insane to have TimeAMString = 'PM' and vice versa
  613. if (AnsiCompareText(AmPmStr, defs.TimeAMString) = 0) then AmPm := AMPM_AM
  614. else if (AnsiCompareText(AmPmStr, defs.TimePMString) = 0) then AmPm := AMPM_PM
  615. else if (CompareText(AmPmStr, 'AM') = 0) then AmPm := AMPM_AM
  616. else if (CompareText(AmPmStr, 'PM') = 0) then AmPm := AMPM_PM
  617. else Exit; //If text does not match any of these, timestring must be wrong;
  618. //if AM/PM is at beginning of string, then a digit is mandatory after it
  619. if (TimeIndex = tiHour) then
  620. begin
  621. DigitPending := True;
  622. end
  623. //otherwise, no more TimeValues allowed after this
  624. else
  625. begin
  626. TimeIndex := tiMSec + 1;
  627. DigitPending := False;
  628. end;
  629. end;//AM/PM
  630. Inc(Cur)
  631. end;//while
  632. //If we arrive here, parsing the elements has been successfull
  633. //if not at least Hours specified then input is not valid
  634. //when am/pm is specified Hour must be <= 12 and not 0
  635. if (TimeIndex = tiHour) or ((AmPm <> AMPM_None) and ((TimeValues[tiHour] > 12) or (TimeValues[tiHour] = 0))) or DigitPending then Exit;
  636. Result := True;
  637. end;
  638. begin
  639. if separator = #0 then
  640. separator := defs.TimeSeparator;
  641. AmPm := AMPM_None;
  642. if not SplitElements(TimeValues, AmPm) then
  643. begin
  644. ErrorMsg:=Format(SErrInvalidTimeFormat,[StrPas(S, Len)]);
  645. Exit;
  646. end;
  647. if (AmPm=AMPM_PM) and (TimeValues[tiHour]<>12) then Inc(TimeValues[tiHour], 12)
  648. else if (AmPm=AMPM_AM) and (TimeValues[tiHour]=12) then TimeValues[tiHour]:=0;
  649. if not TryEncodeTime(TimeValues[tiHour], TimeValues[tiMin], TimeValues[tiSec], TimeValues[tiMSec], result) Then
  650. //errormsg:='Invalid time.';
  651. ErrorMsg:=Format(SErrInvalidTimeFormat,[StrPas(S, Len)]);
  652. end ;
  653. function StrToTime(const S: PChar; Len : integer; separator : char = #0): TDateTime;
  654. Var
  655. Msg : AnsiString;
  656. begin
  657. Result:=IntStrToTime(Msg,S,Len,DefaultFormatSettings,Separator);
  658. If (Msg<>'') then
  659. Raise EConvertError.Create(Msg);
  660. end;
  661. function StrToTime(const S: string; FormatSettings : TFormatSettings): TDateTime;
  662. Var
  663. Msg : AnsiString;
  664. begin
  665. Result:=IntStrToTime(Msg, PChar(S), length(S), FormatSettings, #0);
  666. If (Msg<>'') then
  667. Raise EConvertError.Create(Msg);
  668. end;
  669. function StrToTime(const s: ShortString; separator : char): TDateTime;
  670. begin
  671. // S[1] always exists for shortstring. Length 0 will trigger an error.
  672. result := StrToTime(@s[1], length(s), separator);
  673. end;
  674. function StrToTime(const s: AnsiString; separator : char): TDateTime;
  675. begin
  676. result := StrToTime(PChar(S), length(s), separator);
  677. end;
  678. function StrToTime(const s: ShortString): TDateTime;
  679. begin
  680. // S[1] always exists for shortstring. Length 0 will trigger an error.
  681. result := StrToTime(@s[1], length(s), #0);
  682. end;
  683. function StrToTime(const s: AnsiString): TDateTime;
  684. begin
  685. result:= StrToTime(PChar(s), length(s), #0);
  686. end;
  687. { StrToDateTime converts the string S to a TDateTime value
  688. if S does not represent a valid date and/or time value
  689. an EConvertError will be raised }
  690. function SplitDateTimeStr(DateTimeStr: AnsiString; const FS: TFormatSettings; out DateStr, TimeStr: AnsiString): Integer;
  691. { Helper function for StrToDateTime
  692. Pre-condition
  693. Date is before Time
  694. If either Date or Time is omitted then see what fits best, a time or a date (issue #0020522)
  695. Date and Time are separated by whitespace (space Tab, Linefeed or carriage return)
  696. FS.DateSeparator can be the same as FS.TimeSeparator (issue #0020522)
  697. If they are both #32 and TrimWhite(DateTimeStr) contains a #32 a date is assumed.
  698. Post-condition
  699. DateStr holds date as string or is empty
  700. TimeStr holds time as string or is empty
  701. Result = number of strings returned, 0 = error
  702. }
  703. const
  704. WhiteSpace = [#9,#10,#13,#32];
  705. Space : String = #32; // String, to avoid error 'Cannot decide what overload to call'
  706. var
  707. p: Integer;
  708. DummyDT: TDateTime;
  709. begin
  710. Result := 0;
  711. DateStr := '';
  712. TimeStr := '';
  713. DateTimeStr := Trim(DateTimeStr);
  714. if Length(DateTimeStr) = 0 then exit;
  715. if (FS.DateSeparator = #32) and (FS.TimeSeparator = #32) and (Pos(#32, DateTimeStr) > 0) then
  716. begin
  717. DateStr:=DateTimeStr;
  718. {
  719. Assume a date: dd [mm [yy]].
  720. Really fancy would be counting the number of whitespace occurrences and decide
  721. and split accordingly
  722. }
  723. Exit(1);
  724. end;
  725. p:=1;
  726. //find separator
  727. if Pos(Space,FS.DateSeparator)=0 then
  728. begin
  729. while (p<Length(DateTimeStr)) and (not (DateTimeStr[p+1] in WhiteSpace)) do
  730. Inc(p);
  731. end
  732. else
  733. begin
  734. p:=Pos(FS.TimeSeparator, DateTimeStr);
  735. if (p<>0) then
  736. repeat
  737. Dec(p);
  738. until (p=0) or (DateTimeStr[p] in WhiteSpace);
  739. end;
  740. //Always fill DateStr, it eases the algorithm later
  741. if (p=0) then
  742. p:=Length(DateTimeStr);
  743. DateStr:=Copy(DateTimeStr,1,p);
  744. TimeStr:=Trim(Copy(DateTimeStr,p+1,MaxInt));
  745. if (Length(TimeStr)<>0) then
  746. Result:=2
  747. else
  748. begin
  749. Result:=1; //found 1 string
  750. // 2 cases when DateTimeStr only contains a time:
  751. // Date/time separator differ, and string contains a timeseparator
  752. // Date/time separators are equal, but transformation to date fails.
  753. if ((FS.DateSeparator<>FS.TimeSeparator) and (Pos(FS.TimeSeparator,DateStr) > 0))
  754. or ((FS.DateSeparator=FS.TimeSeparator) and (not TryStrToDate(DateStr, DummyDT, FS))) then
  755. begin
  756. TimeStr := DateStr;
  757. DateStr := '';
  758. end;
  759. end;
  760. end;
  761. function StrToDateTime(const s: AnsiString; const FormatSettings : TFormatSettings): TDateTime;
  762. var
  763. TimeStr, DateStr: AnsiString;
  764. PartsFound: Integer;
  765. begin
  766. PartsFound := SplitDateTimeStr(S, FormatSettings, DateStr, TimeStr);
  767. case PartsFound of
  768. 0: Result:=StrToDate('');
  769. 1: if (Length(DateStr) > 0) then
  770. Result := StrToDate(DateStr, FormatSettings.ShortDateFormat,FormatSettings.DateSeparator)
  771. else
  772. Result := StrToTime(TimeStr, FormatSettings);
  773. 2: Result := ComposeDateTime(StrTodate(DateStr,FormatSettings.ShortDateFormat,FormatSettings.DateSeparator),
  774. StrToTime(TimeStr,FormatSettings));
  775. end;
  776. end;
  777. function StrToDateTime(const s: AnsiString): TDateTime;
  778. begin
  779. Result:=StrToDateTime(S,DefaultFormatSettings);
  780. end;
  781. function StrToDateTime(const s: ShortString; const FormatSettings : TFormatSettings): TDateTime;
  782. var
  783. A : AnsiString;
  784. begin
  785. A:=S;
  786. Result:=StrToDateTime(A,FormatSettings);
  787. end;
  788. { FormatDateTime formats DateTime to the given format string FormatStr }
  789. function FormatDateTime(const FormatStr: string; DateTime: TDateTime; Options : TFormatDateTimeOptions = []): string;
  790. begin
  791. DateTimeToString(Result, FormatStr, DateTime, DefaultFormatSettings,Options);
  792. end;
  793. function FormatDateTime(const FormatStr: string; DateTime: TDateTime; const FormatSettings: TFormatSettings; Options : TFormatDateTimeOptions = []): string;
  794. begin
  795. DateTimeToString(Result, FormatStr, DateTime, FormatSettings,Options);
  796. end;
  797. { DateTimeToString formats DateTime to the given format in FormatStr }
  798. procedure DateTimeToString(out Result: string; const FormatStr: string;
  799. const DateTime: TDateTime; Options : TFormatDateTimeOptions = []);
  800. begin
  801. DateTimeToString(Result, FormatStr, DateTime, DefaultFormatSettings, Options);
  802. end;
  803. procedure DateTimeToString(out Result: string; const FormatStr: string; const DateTime: TDateTime;
  804. const FormatSettings: TFormatSettings; Options : TFormatDateTimeOptions = []);
  805. var
  806. ResultLen: integer;
  807. ResultBuffer: array[0..255] of char;
  808. ResultCurrent: pchar;
  809. {$if defined(win32) or defined(win64)}
  810. isEnable_E_Format : Boolean;
  811. isEnable_G_Format : Boolean;
  812. eastasiainited : boolean;
  813. procedure InitEastAsia;
  814. var ALCID : LCID;
  815. PriLangID , SubLangID : Word;
  816. begin
  817. ALCID := GetThreadLocale;
  818. PriLangID := ALCID and $3FF;
  819. if (PriLangID>0) then
  820. SubLangID := (ALCID and $FFFF) shr 10
  821. else
  822. begin
  823. PriLangID := SysLocale.PriLangID;
  824. SubLangID := SysLocale.SubLangID;
  825. end;
  826. isEnable_E_Format := (PriLangID = LANG_JAPANESE)
  827. or
  828. (PriLangID = LANG_KOREAN)
  829. or
  830. ((PriLangID = LANG_CHINESE)
  831. and
  832. (SubLangID = SUBLANG_CHINESE_TRADITIONAL)
  833. );
  834. isEnable_G_Format := (PriLangID = LANG_JAPANESE)
  835. or
  836. ((PriLangID = LANG_CHINESE)
  837. and
  838. (SubLangID = SUBLANG_CHINESE_TRADITIONAL)
  839. );
  840. eastasiainited :=true;
  841. end;
  842. {$endif win32 or win64}
  843. procedure StoreStr(Str: PChar; Len: Integer);
  844. begin
  845. if ResultLen + Len < SizeOf(ResultBuffer) then
  846. begin
  847. StrMove(ResultCurrent, Str, Len);
  848. ResultCurrent := ResultCurrent + Len;
  849. ResultLen := ResultLen + Len;
  850. end;
  851. end;
  852. procedure StoreString(const Str: string);
  853. var Len: integer;
  854. begin
  855. Len := Length(Str);
  856. if ResultLen + Len < SizeOf(ResultBuffer) then
  857. begin
  858. StrMove(ResultCurrent, pchar(Str), Len);
  859. ResultCurrent := ResultCurrent + Len;
  860. ResultLen := ResultLen + Len;
  861. end;
  862. end;
  863. procedure StoreInt(Value, Digits: Integer);
  864. var
  865. S: string[16];
  866. Len: integer;
  867. begin
  868. System.Str(Value:Digits, S);
  869. for Len := 1 to Length(S) do
  870. begin
  871. if S[Len] = ' ' then
  872. S[Len] := '0'
  873. else
  874. Break;
  875. end;
  876. StoreStr(pchar(@S[1]), Length(S));
  877. end ;
  878. var
  879. Year, Month, Day, DayOfWeek, Hour, Minute, Second, MilliSecond: word;
  880. function FullDays(ADateTime: TDateTime): Integer;
  881. begin
  882. if ADateTime < 0 then ADateTime := -ADateTime;
  883. Result := trunc(ADateTime);
  884. if (frac(ADateTime) > 0.9) and (Hour = 0) and (Minute = 0) and (Second = 0) and (Millisecond = 0) then
  885. inc(Result);
  886. end;
  887. procedure StoreFormat(const FormatStr: string; Nesting: Integer; TimeFlag: Boolean);
  888. var
  889. Token, lastformattoken, prevlasttoken: char;
  890. FormatCurrent: pchar;
  891. FormatEnd: pchar;
  892. Count: integer;
  893. Clock12: boolean;
  894. P: pchar;
  895. tmp: integer;
  896. isInterval: Boolean;
  897. begin
  898. if Nesting > 1 then // 0 is original string, 1 is included FormatString
  899. Exit;
  900. FormatCurrent := PChar(FormatStr);
  901. FormatEnd := FormatCurrent + Length(FormatStr);
  902. Clock12 := false;
  903. isInterval := false;
  904. P := FormatCurrent;
  905. // look for unquoted 12-hour clock token
  906. while P < FormatEnd do
  907. begin
  908. Token := P^;
  909. case Token of
  910. '''', '"':
  911. begin
  912. Inc(P);
  913. while (P < FormatEnd) and (P^ <> Token) do
  914. Inc(P);
  915. end;
  916. 'A', 'a':
  917. begin
  918. if (StrLIComp(P, 'A/P', 3) = 0) or
  919. (StrLIComp(P, 'AMPM', 4) = 0) or
  920. (StrLIComp(P, 'AM/PM', 5) = 0) then
  921. begin
  922. Clock12 := true;
  923. break;
  924. end;
  925. end;
  926. end; // case
  927. Inc(P);
  928. end ;
  929. token := #255;
  930. lastformattoken := ' ';
  931. prevlasttoken := 'H';
  932. while FormatCurrent < FormatEnd do
  933. begin
  934. Token := UpCase(FormatCurrent^);
  935. Count := 1;
  936. P := FormatCurrent + 1;
  937. case Token of
  938. '''', '"':
  939. begin
  940. while (P < FormatEnd) and (p^ <> Token) do
  941. Inc(P);
  942. Inc(P);
  943. Count := P - FormatCurrent;
  944. StoreStr(FormatCurrent + 1, Count - 2);
  945. end ;
  946. 'A':
  947. begin
  948. if StrLIComp(FormatCurrent, 'AMPM', 4) = 0 then
  949. begin
  950. Count := 4;
  951. if Hour < 12 then
  952. StoreString(FormatSettings.TimeAMString)
  953. else
  954. StoreString(FormatSettings.TimePMString);
  955. end
  956. else if StrLIComp(FormatCurrent, 'AM/PM', 5) = 0 then
  957. begin
  958. Count := 5;
  959. if Hour < 12 then StoreStr(FormatCurrent, 2)
  960. else StoreStr(FormatCurrent+3, 2);
  961. end
  962. else if StrLIComp(FormatCurrent, 'A/P', 3) = 0 then
  963. begin
  964. Count := 3;
  965. if Hour < 12 then StoreStr(FormatCurrent, 1)
  966. else StoreStr(FormatCurrent+2, 1);
  967. end
  968. else
  969. raise EConvertError.Create('Illegal character in format string');
  970. end ;
  971. '/': if FormatSettings.DateSeparator<>#0 then StoreStr(@FormatSettings.DateSeparator, 1);
  972. ':': if FormatSettings.TimeSeparator<>#0 then StoreStr(@FormatSettings.TimeSeparator, 1);
  973. '[': if (fdoInterval in Options) then isInterval := true else StoreStr(FormatCurrent, 1);
  974. ']': if (fdoInterval in Options) then isInterval := false else StoreStr(FormatCurrent, 1);
  975. ' ', 'C', 'D', 'H', 'M', 'N', 'S', 'T', 'Y', 'Z', 'F' {$IFDEF MSWindows}, 'G', 'E'{$ENDIF MSWindows} :
  976. begin
  977. while (P < FormatEnd) and (UpCase(P^) = Token) do
  978. Inc(P);
  979. Count := P - FormatCurrent;
  980. case Token of
  981. ' ': StoreStr(FormatCurrent, Count);
  982. 'Y': begin
  983. if Count > 2 then
  984. StoreInt(Year, 4)
  985. else
  986. StoreInt(Year mod 100, 2);
  987. end;
  988. 'M': begin
  989. if isInterval and ((prevlasttoken = 'H') or TimeFlag) then
  990. StoreInt(Minute + (Hour + FullDays(DateTime)*24)*60, 0)
  991. else
  992. if (lastformattoken = 'H') or TimeFlag then
  993. begin
  994. if Count = 1 then
  995. StoreInt(Minute, 0)
  996. else
  997. StoreInt(Minute, 2);
  998. end
  999. else
  1000. begin
  1001. case Count of
  1002. 1: StoreInt(Month, 0);
  1003. 2: StoreInt(Month, 2);
  1004. 3: StoreString(FormatSettings.ShortMonthNames[Month]);
  1005. else
  1006. StoreString(FormatSettings.LongMonthNames[Month]);
  1007. end;
  1008. end;
  1009. end;
  1010. 'D': begin
  1011. case Count of
  1012. 1: StoreInt(Day, 0);
  1013. 2: StoreInt(Day, 2);
  1014. 3: StoreString(FormatSettings.ShortDayNames[DayOfWeek]);
  1015. 4: StoreString(FormatSettings.LongDayNames[DayOfWeek]);
  1016. 5: StoreFormat(FormatSettings.ShortDateFormat, Nesting+1, False);
  1017. else
  1018. StoreFormat(FormatSettings.LongDateFormat, Nesting+1, False);
  1019. end ;
  1020. end ;
  1021. 'H':
  1022. if isInterval then
  1023. StoreInt(Hour + FullDays(DateTime)*24, Count)
  1024. else
  1025. if Clock12 then
  1026. begin
  1027. tmp := hour mod 12;
  1028. if tmp=0 then tmp:=12;
  1029. if Count = 1 then
  1030. StoreInt(tmp, 0)
  1031. else
  1032. StoreInt(tmp, 2);
  1033. end
  1034. else begin
  1035. if Count = 1 then
  1036. StoreInt(Hour, 0)
  1037. else
  1038. StoreInt(Hour, 2);
  1039. end;
  1040. 'N': if isInterval then
  1041. StoreInt(Minute + (Hour + FullDays(DateTime)*24)*60, Count)
  1042. else
  1043. if Count = 1 then
  1044. StoreInt(Minute, 0)
  1045. else
  1046. StoreInt(Minute, 2);
  1047. 'S': if isInterval then
  1048. StoreInt(Second + (Minute + (Hour + FullDays(DateTime)*24)*60)*60, Count)
  1049. else
  1050. if Count = 1 then
  1051. StoreInt(Second, 0)
  1052. else
  1053. StoreInt(Second, 2);
  1054. 'Z': if Count = 1 then
  1055. StoreInt(MilliSecond, 0)
  1056. else
  1057. StoreInt(MilliSecond, 3);
  1058. 'T': if Count = 1 then
  1059. StoreFormat(FormatSettings.ShortTimeFormat, Nesting+1, True)
  1060. else
  1061. StoreFormat(FormatSettings.LongTimeFormat, Nesting+1, True);
  1062. 'C': begin
  1063. StoreFormat(FormatSettings.ShortDateFormat, Nesting+1, False);
  1064. if (Hour<>0) or (Minute<>0) or (Second<>0) then
  1065. begin
  1066. StoreString(' ');
  1067. StoreFormat(FormatSettings.LongTimeFormat, Nesting+1, True);
  1068. end;
  1069. end;
  1070. 'F': begin
  1071. StoreFormat(FormatSettings.ShortDateFormat, Nesting+1, False);
  1072. StoreString(' ');
  1073. StoreFormat(FormatSettings.LongTimeFormat, Nesting+1, True);
  1074. end;
  1075. {$if defined(win32) or defined(win64)}
  1076. 'E':
  1077. begin
  1078. if not Eastasiainited then InitEastAsia;
  1079. if Not(isEnable_E_Format) then StoreStr(FormatCurrent, 1)
  1080. else
  1081. begin
  1082. while (P < FormatEnd) and (UpCase(P^) = Token) do
  1083. P := P + 1;
  1084. Count := P - FormatCurrent;
  1085. StoreString(ConvertEraYearString(Count,Year,Month,Day));
  1086. end;
  1087. prevlasttoken := lastformattoken;
  1088. lastformattoken:=token;
  1089. end;
  1090. 'G':
  1091. begin
  1092. if not Eastasiainited then InitEastAsia;
  1093. if Not(isEnable_G_Format) then StoreStr(FormatCurrent, 1)
  1094. else
  1095. begin
  1096. while (P < FormatEnd) and (UpCase(P^) = Token) do
  1097. P := P + 1;
  1098. Count := P - FormatCurrent;
  1099. StoreString(ConvertEraString(Count,Year,Month,Day));
  1100. end;
  1101. prevlasttoken := lastformattoken;
  1102. lastformattoken:=token;
  1103. end;
  1104. {$endif win32 or win64}
  1105. end;
  1106. prevlasttoken := lastformattoken;
  1107. lastformattoken := token;
  1108. end;
  1109. else
  1110. StoreStr(@Token, 1);
  1111. end ;
  1112. Inc(FormatCurrent, Count);
  1113. end;
  1114. end;
  1115. begin
  1116. {$if defined(win32) or defined(win64)}
  1117. eastasiainited:=false;
  1118. {$endif win32 or win64}
  1119. DecodeDateFully(DateTime, Year, Month, Day, DayOfWeek);
  1120. DecodeTime(DateTime, Hour, Minute, Second, MilliSecond);
  1121. ResultLen := 0;
  1122. ResultCurrent := @ResultBuffer[0];
  1123. if FormatStr <> '' then
  1124. StoreFormat(FormatStr, 0, False)
  1125. else
  1126. StoreFormat('C', 0, False);
  1127. ResultBuffer[ResultLen] := #0;
  1128. result := StrPas(@ResultBuffer[0]);
  1129. if (DateTime < 0) and (fdoInterval in Options) then
  1130. result := '-' + result;
  1131. end ;
  1132. Function DateTimeToFileDate(DateTime : TDateTime) : Int64;
  1133. Var YY,MM,DD,H,m,s,msec : Word;
  1134. begin
  1135. Decodedate (DateTime,YY,MM,DD);
  1136. DecodeTime (DateTime,h,m,s,msec);
  1137. {$if not defined(unix) and not defined(wasi)}
  1138. If (YY<1980) or (YY>2099) then
  1139. Result:=0
  1140. else
  1141. begin
  1142. Result:=(s shr 1) or (m shl 5) or (h shl 11);
  1143. Result:=Result or longint(DD shl 16 or (MM shl 21) or (word(YY-1980) shl 25));
  1144. end;
  1145. {$else unix or wasi}
  1146. Result:=LocalToEpoch(yy,mm,dd,h,m,s);
  1147. {$endif unix or wasi}
  1148. end;
  1149. Function UniversalToFileDate(DateTime : TDateTime) : int64;
  1150. {$if not defined(unix) and not defined(wasi)}
  1151. begin
  1152. Result := DateTimeToFileDate(UniversalTimeToLocal(DateTime));
  1153. end;
  1154. {$else unix or wasi}
  1155. Var YY,MM,DD,H,m,s,msec : Word;
  1156. begin
  1157. Decodedate (DateTime,YY,MM,DD);
  1158. DecodeTime (DateTime,h,m,s,msec);
  1159. Result:=UniversalToEpoch(yy,mm,dd,h,m,s);
  1160. end;
  1161. {$endif unix or wasi}
  1162. function CurrentYear: Word;
  1163. var
  1164. SysTime: TSystemTime;
  1165. begin
  1166. GetLocalTime(SysTime);
  1167. Result := SysTime.Year;
  1168. end;
  1169. Function FileDateToDateTime (Filedate : Int64) : TDateTime;
  1170. {$if not defined(unix) and not defined(wasi)}
  1171. Var Date,Time : Word;
  1172. begin
  1173. Date:=FileDate shr 16;
  1174. Time:=FileDate and $ffff;
  1175. Result:=ComposeDateTime(EncodeDate((Date shr 9) + 1980,(Date shr 5) and 15, Date and 31),
  1176. EncodeTime(Time shr 11, (Time shr 5) and 63, (Time and 31) shl 1,0));
  1177. end;
  1178. {$else unix or wasi}
  1179. var
  1180. y, mon, d, h, min, s: word;
  1181. begin
  1182. EpochToLocal(FileDate,y,mon,d,h,min,s);
  1183. Result:=ComposeDateTime(EncodeDate(y,mon,d),EncodeTime(h,min,s,0));
  1184. end;
  1185. {$endif unix or wasi}
  1186. Function FileDateToUniversal (Filedate : Int64) : TDateTime;
  1187. {$if not defined(unix) and not defined(wasi)}
  1188. begin
  1189. Result := LocalTimeToUniversal(FileDateToDateTime(Filedate));
  1190. end;
  1191. {$else unix or wasi}
  1192. var
  1193. y, mon, d, h, min, s: word;
  1194. begin
  1195. EpochToUniversal(FileDate,y,mon,d,h,min,s);
  1196. Result:=ComposeDateTime(EncodeDate(y,mon,d),EncodeTime(h,min,s,0));
  1197. end;
  1198. {$endif unix or wasi}
  1199. function TryStrToDate(const S: ShortString; out Value: TDateTime): Boolean;
  1200. begin
  1201. result := TryStrToDate(S, Value, #0);
  1202. end;
  1203. function TryStrToDate(const S: ShortString; out Value: TDateTime;
  1204. const useformat : string; separator : char = #0): Boolean;
  1205. Var
  1206. Msg : Ansistring;
  1207. begin
  1208. // S[1] always exists for shortstring. Length 0 will trigger an error.
  1209. Value:=IntStrToDate(Msg,@S[1],Length(S),useformat,defaultformatsettings,separator);
  1210. Result:=(Msg='');
  1211. end;
  1212. function TryStrToDate(const S: AnsiString; out Value: TDateTime;
  1213. const useformat : string; separator : char = #0): Boolean;
  1214. Var
  1215. Msg : Ansistring;
  1216. begin
  1217. Result:=Length(S)<>0;
  1218. If Result then
  1219. begin
  1220. Value:=IntStrToDate(Msg,PChar(S),Length(S),useformat,DefaultFormatSettings,Separator);
  1221. Result:=(Msg='');
  1222. end;
  1223. end;
  1224. function TryStrToDate(const S: ShortString; out Value: TDateTime; separator : char): Boolean;
  1225. begin
  1226. Result:=TryStrToDate(S,Value,DefaultFormatSettings.ShortDateFormat,Separator);
  1227. end;
  1228. function TryStrToDate(const S: AnsiString; out Value: TDateTime): Boolean;
  1229. begin
  1230. Result:=TryStrToDate(S,Value,DefaultFormatSettings.ShortDateFormat,#0);
  1231. end;
  1232. function TryStrToDate(const S: AnsiString; out Value: TDateTime; separator : char): Boolean;
  1233. begin
  1234. Result:=TryStrToDate(S,Value,DefaultFormatSettings.ShortDateFormat,Separator);
  1235. end;
  1236. function TryStrToDate(const S: string; out Value: TDateTime; const FormatSettings: TFormatSettings): Boolean;
  1237. Var
  1238. Msg : Ansistring;
  1239. begin
  1240. Result:=Length(S)<>0;
  1241. If Result then
  1242. begin
  1243. Value:=IntStrToDate(Msg,PChar(S),Length(S),FormatSettings.ShortDateFormat,FormatSettings,#0);
  1244. Result:=(Msg='');
  1245. end;
  1246. end;
  1247. function TryStrToTime(const S: ShortString; out Value: TDateTime; separator : char): Boolean;
  1248. Var
  1249. Msg : AnsiString;
  1250. begin
  1251. // S[1] always exists for shortstring. Length 0 will trigger an error.
  1252. Value:=IntStrToTime(Msg,@S[1],Length(S),DefaultFormatSettings,Separator);
  1253. result:=(Msg='');
  1254. end;
  1255. function TryStrToTime(const S: ShortString; out Value: TDateTime): Boolean;
  1256. begin
  1257. Result := TryStrToTime(S,Value,#0);
  1258. end;
  1259. function TryStrToTime(const S: AnsiString; out Value: TDateTime; separator : char): Boolean;
  1260. Var
  1261. Msg : AnsiString;
  1262. begin
  1263. Result:=Length(S)<>0;
  1264. If Result then
  1265. begin
  1266. Value:=IntStrToTime(Msg,PChar(S),Length(S),DefaultFormatSettings,Separator);
  1267. Result:=(Msg='');
  1268. end;
  1269. end;
  1270. function TryStrToTime(const S: AnsiString; out Value: TDateTime): Boolean;
  1271. begin
  1272. result := TryStrToTime(S,Value,#0);
  1273. end;
  1274. function TryStrToTime(const S: string; out Value: TDateTime; const FormatSettings: TFormatSettings): Boolean;
  1275. Var msg : AnsiString;
  1276. begin
  1277. Result:=Length(S)<>0;
  1278. If Result then
  1279. begin
  1280. Value:=IntStrToTime(Msg,PChar(S),Length(S),FormatSettings,#0);
  1281. Result:=(Msg='');
  1282. end;
  1283. end;
  1284. function TryStrToDateTime(const S: ShortString; out Value: TDateTime): Boolean;
  1285. begin
  1286. result := TryStrToDateTime(S, Value, DefaultFormatSettings);
  1287. end;
  1288. function TryStrToDateTime(const S: AnsiString; out Value: TDateTime): Boolean;
  1289. begin
  1290. result := TryStrToDateTime(S, Value, DefaultFormatSettings);
  1291. end;
  1292. function TryStrToDateTime(const S: string; out Value: TDateTime; const FormatSettings: TFormatSettings): Boolean;
  1293. var
  1294. I: integer;
  1295. dtdate, dttime :TDateTime;
  1296. begin
  1297. result:=false;
  1298. I:=Pos(FormatSettings.TimeSeparator,S);
  1299. If (I>0) then
  1300. begin
  1301. While (I>0) and (S[I]<>' ') do
  1302. Dec(I);
  1303. If I>0 then
  1304. begin
  1305. if not TryStrToDate(Copy(S,1,I-1),dtdate,Formatsettings) then
  1306. exit;
  1307. if not TryStrToTime(Copy(S,i+1, Length(S)-i),dttime,Formatsettings) then
  1308. exit;
  1309. Value:=ComposeDateTime(dtdate,dttime);
  1310. result:=true;
  1311. end
  1312. else
  1313. result:=TryStrToTime(s,Value,Formatsettings);
  1314. end
  1315. else
  1316. result:=TryStrToDate(s,Value,Formatsettings);
  1317. end;
  1318. function StrToDateDef(const S: ShortString; const Defvalue : TDateTime): TDateTime;
  1319. begin
  1320. result := StrToDateDef(S,DefValue,#0);
  1321. end;
  1322. function StrToTimeDef(const S: ShortString; const Defvalue : TDateTime): TDateTime;
  1323. begin
  1324. result := StrToTimeDef(S,DefValue,#0);
  1325. end;
  1326. function StrToDateTimeDef(const S: ShortString; const Defvalue : TDateTime): TDateTime;
  1327. begin
  1328. Result:=StrToDateTimeDef(S,DefValue,DefaultFormatSettings);
  1329. end;
  1330. function StrToDateTimeDef(const S: AnsiString; const Defvalue : TDateTime; const FormatSettings: TFormatSettings): TDateTime;
  1331. begin
  1332. if not TryStrToDateTime(s,Result,FormatSettings) Then
  1333. result:=defvalue;
  1334. end;
  1335. function StrToDateDef(const S: ShortString; const Defvalue : TDateTime; separator : char): TDateTime;
  1336. begin
  1337. if not TryStrToDate(s,Result, separator) Then
  1338. result:=defvalue;
  1339. end;
  1340. function StrToTimeDef(const S: ShortString; const Defvalue : TDateTime; separator : char): TDateTime;
  1341. begin
  1342. if not TryStrToTime(s,Result, separator) Then
  1343. result:=defvalue;
  1344. end;
  1345. function StrToDateDef(const S: AnsiString; const Defvalue : TDateTime): TDateTime;
  1346. begin
  1347. result := StrToDateDef(S,DefValue,#0);
  1348. end;
  1349. function StrToTimeDef(const S: AnsiString; const Defvalue : TDateTime): TDateTime;
  1350. begin
  1351. result := StrToTimeDef(S,DefValue,#0);
  1352. end;
  1353. function StrToDateTimeDef(const S: AnsiString; const Defvalue : TDateTime): TDateTime;
  1354. begin
  1355. if not TryStrToDateTime(s,Result) Then
  1356. result:=defvalue;
  1357. end;
  1358. function StrToDateDef(const S: AnsiString; const Defvalue : TDateTime; separator : char): TDateTime;
  1359. begin
  1360. if not TryStrToDate(s,Result, separator) Then
  1361. result:=defvalue;
  1362. end;
  1363. function StrToTimeDef(const S: AnsiString; const Defvalue : TDateTime; separator : char): TDateTime;
  1364. begin
  1365. if not TryStrToTime(s,Result, separator) Then
  1366. result:=defvalue;
  1367. end;
  1368. procedure ReplaceTime(var dati:TDateTime; NewTime : TDateTime);inline;
  1369. begin
  1370. dati:= ComposeDateTime(dati, newtime);
  1371. end;
  1372. procedure ReplaceDate(var DateTime: TDateTime; const NewDate: TDateTime); inline;
  1373. var
  1374. tmp : TDateTime;
  1375. begin
  1376. tmp:=NewDate;
  1377. ReplaceTime(tmp,DateTime);
  1378. DateTime:=tmp;
  1379. end;
  1380. {$IFNDEF HAS_LOCALTIMEZONEOFFSET}
  1381. Function GetLocalTimeOffset : Integer;
  1382. begin
  1383. Result:=0;
  1384. end;
  1385. function GetLocalTimeOffset(const DateTime: TDateTime; const InputIsUTC: Boolean; out Offset: Integer): Boolean;
  1386. begin
  1387. Result:=False;
  1388. end;
  1389. function GetUniversalTime(var SystemTime: TSystemTime): Boolean;
  1390. begin
  1391. Result:=False;
  1392. end;
  1393. {$ENDIF}
  1394. function GetLocalTimeOffset(const DateTime: TDateTime; const InputIsUTC: Boolean): Integer;
  1395. begin
  1396. if not GetLocalTimeOffset(DateTime, InputIsUTC, Result) then
  1397. Result:=GetLocalTimeOffset();
  1398. end;
  1399. { Conversion of UTC to local time and vice versa }
  1400. function UniversalTimeToLocal(UT: TDateTime): TDateTime;
  1401. begin
  1402. Result:=UniversalTimeToLocal(UT,-GetLocalTimeOffset(UT, True));
  1403. end;
  1404. function UniversalTimeToLocal(UT: TDateTime; TZOffset : Integer): TDateTime;
  1405. begin
  1406. if (TZOffset > 0) then
  1407. Result := UT + EncodeTime(TZOffset div 60, TZOffset mod 60, 0, 0)
  1408. else if (TZOffset < 0) then
  1409. Result := UT - EncodeTime(Abs(TZOffset) div 60, Abs(TZOffset) mod 60, 0, 0)
  1410. else
  1411. Result := UT;
  1412. end;
  1413. Function LocalTimeToUniversal(LT: TDateTime): TDateTime;
  1414. begin
  1415. Result:=LocalTimeToUniversal(LT,-GetLocalTimeOffset(LT, False));
  1416. end;
  1417. Function LocalTimeToUniversal(LT: TDateTime;TZOffset: Integer): TDateTime;
  1418. begin
  1419. if (TZOffset > 0) then
  1420. Result := LT - EncodeTime(TZOffset div 60, TZOffset mod 60, 0, 0)
  1421. else if (TZOffset < 0) then
  1422. Result := LT + EncodeTime(Abs(TZOffset) div 60, Abs(TZOffset) mod 60, 0, 0)
  1423. else
  1424. Result := LT;
  1425. end;