dati.inc 48 KB

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