dcdatetimeutils.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. {
  2. Double Commander
  3. -------------------------------------------------------------------------
  4. Date and time functions.
  5. Copyright (C) 2009-2012 Przemysław Nagay ([email protected])
  6. Copyright (C) 2017-2025 Alexander Koblov ([email protected])
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. }
  18. unit DCDateTimeUtils;
  19. {$mode objfpc}
  20. {$H+}{$R-}{$Q-}
  21. interface
  22. uses
  23. Classes, SysUtils, DCBasicTypes
  24. {$IF DEFINED(MSWINDOWS)}
  25. , Windows
  26. {$ELSEIF DEFINED(UNIX)}
  27. , Unix, UnixUtil, DCUnix
  28. {$ENDIF}
  29. ;
  30. const
  31. DATE_TIME_NULL = TDateTime(2958466.0);
  32. function FileTimeToDateTime(FileTime : DCBasicTypes.TFileTime) : TDateTime;
  33. function FileTimeToDateTimeEx(FileTime : DCBasicTypes.TFileTimeEx) : TDateTime;
  34. function DateTimeToFileTime(DateTime : TDateTime) : DCBasicTypes.TFileTime;
  35. function DateTimeToFileTimeEx(DateTime : TDateTime) : DCBasicTypes.TFileTimeEx;
  36. function FileTimeToWinFileTime(FileTime : DCBasicTypes.TFileTime) : TWinFileTime;
  37. function FileTimeExToWinFileTime(FileTime : DCBasicTypes.TFileTimeEx) : TWinFileTime;
  38. function WinFileTimeToFileTimeEx(FileTime: TWinFileTime) : DCBasicTypes.TFileTimeEx;
  39. {en
  40. Converts system specific UTC time to local time.
  41. }
  42. function FileTimeToLocalFileTime(const FileTime: DCBasicTypes.TFileTime;
  43. out LocalFileTime: DCBasicTypes.TFileTime): LongBool;
  44. {en
  45. Converts system specific local time to UTC time.
  46. }
  47. function LocalFileTimeToFileTime(const LocalFileTime: DCBasicTypes.TFileTime;
  48. out FileTime: DCBasicTypes.TFileTime): LongBool;
  49. {en
  50. Converts Windows UTC file time to Windows local file time.
  51. @param(lpFileTime TWinFileTime structure containing the UTC-based file time)
  52. @param(lpLocalFileTime TWinFileTime structure to receive the converted local file time)
  53. @returns(The function returns @true if successful, @false otherwise)
  54. }
  55. function WinFileTimeToLocalFileTime(const FileTime: TWinFileTime;
  56. out LocalFileTime: TWinFileTime): LongBool;
  57. {en
  58. Converts Windows local file time to Windows UTC file time.
  59. @param(lpLocalFileTime TWinFileTime structure that specifies the local file time)
  60. @param(lpFileTime TWinFileTime structure to receive the converted UTC-based file time)
  61. @returns(The function returns @true if successful, @false otherwise)
  62. }
  63. function WinLocalFileTimeToFileTime(const LocalFileTime: TWinFileTime;
  64. out FileTime: TWinFileTime): LongBool;
  65. {en
  66. Converts Windows UTC file time to a file time in TDateTime format.
  67. @param(ft TWinFileTime structure containing the UTC-based file time)
  68. @returns(File time in TDateTime format)
  69. }
  70. function WinFileTimeToDateTime(ft : TWinFileTime) : TDateTime;
  71. {en
  72. Converts a file time in TDateTime format to Windows UTC file time.
  73. @param(dt File time in TDateTime format)
  74. @returns(Windows UTC-based file time)
  75. }
  76. function DateTimeToWinFileTime(dt : TDateTime) : TWinFileTime;
  77. function DosFileTimeToDateTime(const DosTime: TDosFileTime): TDateTime;
  78. function DateTimeToDosFileTime(const DateTime: TDateTime): TDosFileTime;
  79. {$IFDEF MSWINDOWS}
  80. function VariantTimeToDateTime(VarTime: Double): TDateTime;
  81. function WinFileTimeToDateTime(ft : Windows.FILETIME) : TDateTime; inline; overload;
  82. function WinToDosTime(const WinTime: Windows.FILETIME; var DosTime: TDosFileTime): LongBool; overload;
  83. function DosToWinTime(const DosTime: TDosFileTime; var WinTime: Windows.FILETIME): LongBool; overload;
  84. function WinToDosTime(const WinTime: TWinFileTime; var DosTime: TDosFileTime): LongBool;
  85. function DosToWinTime(const DosTime: TDosFileTime; var WinTime: TWinFileTime): LongBool;
  86. {$ENDIF}
  87. function UnixFileTimeToDateTime(UnixTime: TUnixFileTime) : TDateTime;
  88. {$IFDEF UNIX}
  89. function UnixFileTimeToDateTimeEx(UnixTime: DCBasicTypes.TFileTimeEx) : TDateTime;
  90. {$ENDIF}
  91. function DateTimeToUnixFileTime(DateTime: TDateTime) : TUnixFileTime;
  92. function DateTimeToUnixFileTimeEx(DateTime: TDateTime) : DCBasicTypes.TFileTimeEx;
  93. function UnixFileTimeToFileTime(UnixTime: TUnixFileTime): DCBasicTypes.TFileTime;
  94. function UnixFileTimeToDosTime(UnixTime: TUnixFileTime): TDosFileTime;
  95. function DosTimeToUnixFileTime(DosTime: TDosFileTime): TUnixFileTime;
  96. function UnixFileTimeToWinTime(UnixTime: TUnixFileTime): TWinFileTime;
  97. function WinFileTimeToUnixTime(WinTime: TWinFileTime) : TUnixFileTime;
  98. function WinFileTimeToDosTime(FileTime: TWinFileTime): TDosFileTime;
  99. function DosTimeToWinFileTime(FileTime: TDosFileTime): TWinFileTime;
  100. function WcxFileTimeToFileTime(WcxTime: LongInt): DCBasicTypes.TFileTime; inline;
  101. function FileTimeToWcxFileTime(FileTime: DCBasicTypes.TFileTime): LongInt; inline;
  102. function WcxFileTimeToDateTime(WcxTime: LongInt): TDateTime;
  103. function UnixFileTimeToWcxTime(UnixTime: TUnixFileTime): LongInt;
  104. function GetTimeZoneBias: LongInt;
  105. {en
  106. Converts a month short name to month number.
  107. @param(ShortMonthName Month short name)
  108. @param(Default Default month number)
  109. @returns(Month number)
  110. }
  111. function MonthToNumberDef(const ShortMonthName: String; Default: Word): Word;
  112. {en
  113. Converts a year short record to year long record if need (10 -> 2010).
  114. @param(Year Year short record)
  115. @returns(Year long record)
  116. }
  117. function YearShortToLong(Year: Word): Word;
  118. function TwelveToTwentyFour(Hour: Word; Modifier: AnsiString): Word;
  119. function FileTimeCompare(SourceTime, TargetTime: TDateTime; NtfsShift: Boolean): Integer;
  120. type
  121. EDateOutOfRange = class(EConvertError)
  122. private
  123. FDateTime: TDateTime;
  124. public
  125. constructor Create(ADateTime: TDateTime);
  126. property DateTime: TDateTime read FDateTime;
  127. end;
  128. implementation
  129. uses
  130. DateUtils;
  131. const
  132. UnixWinEpoch = TWinFileTime($019DB1DED53E8000); // Unix epoch start
  133. MinWinUnixSec = (0 - TUnixFileTime(UnixWinEpoch div 10000000 - 1));
  134. MaxWinUnixSec = TUnixFileTime(High(TWinFileTime) div 10000000 - 1);
  135. const { Short names of months. }
  136. ShortMonthNames: TMonthNameArray = ('Jan','Feb','Mar','Apr','May','Jun',
  137. 'Jul','Aug','Sep','Oct','Nov','Dec');
  138. {$IF DEFINED(MSWINDOWS)}
  139. var
  140. WinTimeZoneBias: LongInt;
  141. TzSpecificLocalTimeToSystemTime: function(lpTimeZoneInformation: PTimeZoneInformation;
  142. lpLocalTime, lpUniversalTime: PSystemtime): BOOL; stdcall;
  143. {$ENDIF}
  144. function AdjustUnixFileTime(const FileTime: DCBasicTypes.TFileTime;
  145. out AdjustedFileTime: DCBasicTypes.TFileTime;
  146. AdjustValue: Int64): Boolean;
  147. begin
  148. if AdjustValue < 0 then
  149. begin
  150. if FileTime < DCBasicTypes.TFileTime(-AdjustValue) then
  151. begin
  152. AdjustedFileTime := 0;
  153. Result := False;
  154. end
  155. else
  156. begin
  157. AdjustedFileTime := FileTime - DCBasicTypes.TFileTime(-AdjustValue);
  158. Result := True;
  159. end;
  160. end
  161. else
  162. begin
  163. if High(FileTime) - FileTime < DCBasicTypes.TFileTime(AdjustValue) then
  164. begin
  165. AdjustedFileTime := High(FileTime);
  166. Result := False;
  167. end
  168. else
  169. begin
  170. AdjustedFileTime := FileTime + DCBasicTypes.TFileTime(AdjustValue);
  171. Result := True;
  172. end;
  173. end;
  174. end;
  175. function AdjustWinFileTime(const FileTime: TWinFileTime;
  176. out AdjustedFileTime: TWinFileTime;
  177. AdjustValue: Int64): Boolean;
  178. begin
  179. if AdjustValue < 0 then
  180. begin
  181. if FileTime < DCBasicTypes.TWinFileTime(-AdjustValue) then
  182. begin
  183. AdjustedFileTime := 0;
  184. Result := False;
  185. end
  186. else
  187. begin
  188. AdjustedFileTime := FileTime - DCBasicTypes.TWinFileTime(-AdjustValue);
  189. Result := True;
  190. end;
  191. end
  192. else
  193. begin
  194. if High(FileTime) - FileTime < DCBasicTypes.TWinFileTime(AdjustValue) then
  195. begin
  196. AdjustedFileTime := High(FileTime);
  197. Result := False;
  198. end
  199. else
  200. begin
  201. AdjustedFileTime := FileTime + DCBasicTypes.TWinFileTime(AdjustValue);
  202. Result := True;
  203. end;
  204. end;
  205. end;
  206. function FileTimeToDateTime(FileTime : DCBasicTypes.TFileTime) : TDateTime; inline;
  207. {$IF DEFINED(MSWINDOWS)}
  208. begin
  209. Result := WinFileTimeToDateTime(FileTime);
  210. end;
  211. {$ELSEIF DEFINED(UNIX)}
  212. begin
  213. Result := UnixFileTimeToDateTime(FileTime);
  214. end;
  215. {$ELSE}
  216. begin
  217. Result := 0;
  218. end;
  219. {$ENDIF}
  220. function FileTimeToDateTimeEx(FileTime : DCBasicTypes.TFileTimeEx) : TDateTime;
  221. {$IF DEFINED(MSWINDOWS)}
  222. begin
  223. Result := WinFileTimeToDateTime(FileTime);
  224. end;
  225. {$ELSEIF DEFINED(UNIX)}
  226. begin
  227. Result := UnixFileTimeToDateTimeEx(FileTime);
  228. end;
  229. {$ELSE}
  230. begin
  231. Result := 0;
  232. end;
  233. {$ENDIF}
  234. function DateTimeToFileTime(DateTime : TDateTime) : DCBasicTypes.TFileTime; inline;
  235. {$IF DEFINED(MSWINDOWS)}
  236. begin
  237. Result := DateTimeToWinFileTime(DateTime);
  238. end;
  239. {$ELSEIF DEFINED(UNIX)}
  240. begin
  241. Result := DateTimeToUnixFileTime(DateTime);
  242. end;
  243. {$ELSE}
  244. begin
  245. Result := 0;
  246. end;
  247. {$ENDIF}
  248. function DateTimeToFileTimeEx(DateTime : TDateTime) : DCBasicTypes.TFileTimeEx; inline;
  249. {$IF DEFINED(MSWINDOWS)}
  250. begin
  251. Result := DateTimeToWinFileTime(DateTime);
  252. end;
  253. {$ELSEIF DEFINED(UNIX)}
  254. begin
  255. Result := DateTimeToUnixFileTimeEx(DateTime);
  256. end;
  257. {$ELSE}
  258. begin
  259. Result := 0;
  260. end;
  261. {$ENDIF}
  262. function FileTimeToWinFileTime(FileTime: DCBasicTypes.TFileTime): TWinFileTime; inline;
  263. {$IF DEFINED(MSWINDOWS)}
  264. begin
  265. Result:= TWinFileTime(FileTime)
  266. end;
  267. {$ELSEIF DEFINED(UNIX)}
  268. begin
  269. Result:= UnixFileTimeToWinTime(TUnixFileTime(FileTime));
  270. end;
  271. {$ENDIF}
  272. function FileTimeExToWinFileTime(FileTime: DCBasicTypes.TFileTimeEx): TWinFileTime;
  273. {$IF DEFINED(MSWINDOWS)}
  274. begin
  275. Result:= TWinFileTime(FileTime)
  276. end;
  277. {$ELSEIF DEFINED(UNIX)}
  278. begin
  279. if (FileTime.Sec > MaxWinUnixSec) then
  280. Result:= High(TWinFileTime)
  281. else if (FileTime.Sec < MinWinUnixSec) then
  282. Result:= Low(TWinFileTime)
  283. else begin
  284. Result:= UnixWinEpoch + FileTime.sec * 10000000 + FileTime.nanosec div 100;
  285. end;
  286. end;
  287. {$ENDIF}
  288. function WinFileTimeToFileTimeEx(FileTime: TWinFileTime): DCBasicTypes.TFileTimeEx;
  289. {$IF DEFINED(MSWINDOWS)}
  290. begin
  291. Result := TFileTimeEx(FileTime);
  292. end;
  293. {$ELSEIF DEFINED(UNIX)}
  294. begin
  295. if (FileTime >= UnixWinEpoch) then
  296. begin
  297. Result.Sec:= Int64((FileTime - UnixWinEpoch) div 10000000);
  298. Result.NanoSec:= Int64((FileTime - UnixWinEpoch) mod 10000000) * 100;
  299. end
  300. else begin
  301. Result.Sec:= (Int64(FileTime) - Int64(UnixWinEpoch)) div 10000000;
  302. if (Result.Sec = 0) then
  303. Result.NanoSec:= 0
  304. else begin
  305. Result.NanoSec:= (Int64(UnixWinEpoch - FileTime) mod 10000000) * 100;
  306. if (Result.NanoSec > 0) then Result.NanoSec:= 1000000000 - Result.NanoSec;
  307. end;
  308. end;
  309. end;
  310. {$ENDIF}
  311. function FileTimeToLocalFileTime(const FileTime: DCBasicTypes.TFileTime;
  312. out LocalFileTime: DCBasicTypes.TFileTime): LongBool;
  313. {$IFDEF MSWINDOWS}
  314. begin
  315. Result := Windows.FileTimeToLocalFileTime(@Windows.FILETIME(FileTime), @Windows.FILETIME(LocalFileTime));
  316. end;
  317. {$ELSE}
  318. begin
  319. Result := AdjustUnixFileTime(FileTime, LocalFileTime, Tzseconds);
  320. end;
  321. {$ENDIF}
  322. function LocalFileTimeToFileTime(const LocalFileTime: DCBasicTypes.TFileTime;
  323. out FileTime: DCBasicTypes.TFileTime): LongBool;
  324. {$IFDEF MSWINDOWS}
  325. begin
  326. Result := Windows.LocalFileTimeToFileTime(@Windows.FILETIME(LocalFileTime), @Windows.FILETIME(FileTime));
  327. end;
  328. {$ELSE}
  329. begin
  330. Result := AdjustUnixFileTime(LocalFileTime, FileTime, -Tzseconds);
  331. end;
  332. {$ENDIF}
  333. function WinFileTimeToLocalFileTime(const FileTime: TWinFileTime;
  334. out LocalFileTime: TWinFileTime): LongBool;
  335. {$IFDEF MSWINDOWS}
  336. begin
  337. Result := Windows.FileTimeToLocalFileTime(@Windows.FILETIME(FileTime), @Windows.FILETIME(LocalFileTime));
  338. end;
  339. {$ELSE}
  340. begin
  341. Result := AdjustWinFileTime(FileTime, LocalFileTime, 10000000 * Int64(TZSeconds));
  342. end;
  343. {$ENDIF}
  344. function WinLocalFileTimeToFileTime(const LocalFileTime: TWinFileTime;
  345. out FileTime: TWinFileTime): LongBool;
  346. {$IFDEF MSWINDOWS}
  347. begin
  348. Result := Windows.LocalFileTimeToFileTime(@Windows.FILETIME(LocalFileTime), @Windows.FILETIME(FileTime));
  349. end;
  350. {$ELSE}
  351. begin
  352. Result := AdjustWinFileTime(LocalFileTime, FileTime, -10000000 * Int64(TZSeconds));
  353. end;
  354. {$ENDIF}
  355. function WinFileTimeToDateTime(ft : TWinFileTime) : TDateTime;
  356. {$IF DEFINED(MSWINDOWS)}
  357. var
  358. lpUniversalTime, lpLocalTime: TSystemTime;
  359. begin
  360. if (Win32MajorVersion > 5) then
  361. begin
  362. FileTimeToSystemTime(@ft, @lpUniversalTime);
  363. SystemTimeToTzSpecificLocalTime(nil, @lpUniversalTime, @lpLocalTime);
  364. Result := SystemTimeToDateTime(lpLocalTime);
  365. end
  366. else
  367. begin
  368. WinFileTimeToLocalFileTime(ft,ft);
  369. Result := (ft / 864000000000.0) - 109205.0;
  370. end;
  371. end;
  372. {$ELSE}
  373. begin
  374. Result := FileTimeToDateTimeEx(WinFileTimeToFileTimeEx(ft));
  375. end;
  376. {$ENDIF}
  377. function DateTimeToWinFileTime(dt : TDateTime) : TWinFileTime;
  378. {$IF DEFINED(MSWINDOWS)}
  379. var
  380. lpUniversalTime, lpLocalTime: TSystemTime;
  381. begin
  382. if (Win32MajorVersion > 5) then
  383. begin
  384. DateTimeToSystemTime(dt, lpLocalTime);
  385. TzSpecificLocalTimeToSystemTime(nil, @lpLocalTime, @lpUniversalTime);
  386. SystemTimeToFileTime(@lpUniversalTime, @Result);
  387. end
  388. else
  389. begin
  390. Result := Round((Extended(dt) + 109205.0) * 864000000000.0);
  391. WinLocalFileTimeToFileTime(Result, Result);
  392. end;
  393. end;
  394. {$ELSE}
  395. begin
  396. Result := FileTimeExToWinFileTime(DateTimeToFileTimeEx(dt));
  397. end;
  398. {$ENDIF}
  399. function DosFileTimeToDateTime(const DosTime: TDosFileTime): TDateTime;
  400. var
  401. Yr, Mo, Dy : Word;
  402. Hr, Mn, S : Word;
  403. FileDate, FileTime : Word;
  404. begin
  405. FileDate := LongRec(DosTime).Hi;
  406. FileTime := LongRec(DosTime).Lo;
  407. Yr := FileDate shr 9 + 1980;
  408. Mo := FileDate shr 5 and 15;
  409. if Mo < 1 then Mo := 1;
  410. if Mo > 12 then Mo := 12;
  411. Dy := FileDate and 31;
  412. if Dy < 1 then Dy := 1;
  413. if Dy > DaysInAMonth(Yr, Mo) then
  414. Dy := DaysInAMonth(Yr, Mo);
  415. Hr := FileTime shr 11;
  416. if Hr > 23 then Hr := 23;
  417. Mn := FileTime shr 5 and 63;
  418. if Mn > 59 then Mn := 59;
  419. S := FileTime and 31 shl 1;
  420. if S > 59 then S := 59;
  421. Result := ComposeDateTime(EncodeDate(Yr, Mo, Dy),
  422. EncodeTime(Hr, Mn, S, 0));
  423. end;
  424. function DateTimeToDosFileTime(const DateTime: TDateTime): TDosFileTime;
  425. var
  426. Yr, Mo, Dy : Word;
  427. Hr, Mn, S, MS: Word;
  428. begin
  429. DecodeDate(DateTime, Yr, Mo, Dy);
  430. DecodeTime(DateTime, Hr, Mn, S, MS);
  431. // Outside DOS file date year range
  432. if (Yr < 1980) then
  433. Yr := 1980
  434. else if (Yr > 2107) then
  435. begin
  436. Yr := 2107;
  437. end;
  438. LongRec(Result).Lo := (S shr 1) or (Mn shl 5) or (Hr shl 11);
  439. LongRec(Result).Hi := Dy or (Mo shl 5) or (Word(Yr - 1980) shl 9);
  440. end;
  441. {$IFDEF MSWINDOWS}
  442. function VariantTimeToDateTime(VarTime: Double): TDateTime;
  443. var
  444. lpUniversalTime, lpLocalTime: TSystemTime;
  445. begin
  446. if (Win32MajorVersion > 5) then
  447. begin
  448. DateTimeToSystemTime(VarTime, lpUniversalTime);
  449. SystemTimeToTzSpecificLocalTime(nil, @lpUniversalTime, @lpLocalTime);
  450. Result := SystemTimeToDateTime(lpLocalTime);
  451. end
  452. else begin
  453. Result := IncMinute(VarTime, -WinTimeZoneBias);
  454. end;
  455. end;
  456. function WinFileTimeToDateTime(ft : Windows.FILETIME) : TDateTime;
  457. begin
  458. Result := WinFileTimeToDateTime(TWinFileTime(ft));
  459. end;
  460. function WinToDosTime(const WinTime: Windows.FILETIME; var DosTime: TDosFileTime): LongBool;
  461. var
  462. lft : Windows.TFILETIME;
  463. begin
  464. Result:= Windows.FileTimeToLocalFileTime(@Windows.FILETIME(WinTime), @lft) and
  465. Windows.FileTimeToDosDateTime(@lft, @LongRec(Dostime).Hi, @LongRec(DosTime).Lo);
  466. end;
  467. function DosToWinTime(const DosTime: TDosFileTime; var WinTime: Windows.FILETIME): LongBool;
  468. var
  469. lft : Windows.TFILETIME;
  470. begin
  471. Result := Windows.DosDateTimeToFileTime(LongRec(DosTime).Hi, LongRec(DosTime).Lo, @lft) and
  472. Windows.LocalFileTimeToFileTime(@lft, @Windows.FILETIME(WinTime));
  473. end;
  474. function WinToDosTime(const WinTime: TWinFileTime; var DosTime: TDosFileTime): LongBool;
  475. var
  476. lft : Windows.TFILETIME;
  477. begin
  478. Result:= Windows.FileTimeToLocalFileTime(@Windows.FILETIME(WinTime), @lft) and
  479. Windows.FileTimeToDosDateTime(@lft, @LongRec(Dostime).Hi, @LongRec(DosTime).Lo);
  480. end;
  481. function DosToWinTime(const DosTime: TDosFileTime; var WinTime: TWinFileTime): LongBool;
  482. var
  483. lft : Windows.TFILETIME;
  484. begin
  485. Result := Windows.DosDateTimeToFileTime(LongRec(DosTime).Hi, LongRec(DosTime).Lo, @lft) and
  486. Windows.LocalFileTimeToFileTime(@lft, @Windows.FILETIME(WinTime));
  487. end;
  488. {$ENDIF}
  489. {$IF DEFINED(UNIX)}
  490. function UnixFileTimeToDateTime(UnixTime: TUnixFileTime) : TDateTime;
  491. var
  492. filetime: DCBasicTypes.TFileTimeEx;
  493. begin
  494. filetime:= TFileTimeEx.create(UnixTime);
  495. Result:= UnixFileTimeToDateTimeEx(filetime);
  496. end;
  497. function UnixFileTimeToDateTimeEx(UnixTime: DCBasicTypes.TFileTimeEx) : TDateTime;
  498. var
  499. ATime: TTimeStruct;
  500. Milliseconds: Word;
  501. begin
  502. if (fpLocalTime(@UnixTime.sec, @ATime) = nil) then
  503. Exit(UnixEpoch);
  504. ATime.tm_mon += 1;
  505. ATime.tm_year += 1900;
  506. if (ATime.tm_year < 1) then
  507. ATime.tm_year := 1
  508. else if (ATime.tm_year > 9999) then
  509. ATime.tm_year := 9999;
  510. if ATime.tm_sec > 59 then
  511. ATime.tm_sec := 59;
  512. if (UnixTime.nanosec > 999000000) then
  513. Milliseconds := 999
  514. else begin
  515. Milliseconds := Round( Extended(UnixTime.nanosec) / (1000.0 * 1000.0) );
  516. end;
  517. Result := ComposeDateTime(EncodeDate(ATime.tm_year, ATime.tm_mon, ATime.tm_mday),
  518. EncodeTime(ATime.tm_hour, ATime.tm_min, ATime.tm_sec, milliseconds));
  519. end;
  520. {$ELSE}
  521. function UnixFileTimeToDateTime(UnixTime: TUnixFileTime) : TDateTime;
  522. var
  523. WinFileTime: TWinFileTime;
  524. begin
  525. WinFileTime:= UnixFileTimeToWinTime(UnixTime);
  526. Result:= WinFileTimeToDateTime(WinFileTime);
  527. end;
  528. {$ENDIF}
  529. function DateTimeToUnixFileTime(DateTime : TDateTime): TUnixFileTime;
  530. {$IF DEFINED(UNIX)}
  531. var
  532. AUnixTime: TTime;
  533. ATime: TTimeStruct;
  534. Year, Month, Day: Word;
  535. Hour, Minute, Second, MilliSecond: Word;
  536. begin
  537. DecodeDate(DateTime, Year, Month, Day);
  538. DecodeTime(DateTime, Hour, Minute, Second, MilliSecond);
  539. ATime.tm_isdst:= -1;
  540. ATime.tm_year:= Year - 1900;
  541. ATime.tm_mon:= Month - 1;
  542. ATime.tm_mday:= Day;
  543. ATime.tm_hour:= Hour;
  544. ATime.tm_min:= Minute;
  545. ATime.tm_sec:= Second;
  546. AUnixTime:= fpMkTime(@ATime);
  547. if (AUnixTime = -1) then
  548. Result:= 0
  549. else begin
  550. Result:= TUnixFileTime(AUnixTime);
  551. end;
  552. end;
  553. {$ELSE}
  554. var
  555. WinFileTime: TWinFileTime;
  556. begin
  557. WinFileTime:= DateTimeToWinFileTime(DateTime);
  558. Result:= WinFileTimeToUnixTime(WinFileTime);
  559. end;
  560. {$ENDIF}
  561. function DateTimeToUnixFileTimeEx(DateTime : TDateTime): DCBasicTypes.TFileTimeEx;
  562. {$IF DEFINED(UNIX)}
  563. var
  564. AUnixTime: TTime;
  565. ATime: TTimeStruct;
  566. Year, Month, Day: Word;
  567. Hour, Minute, Second, MilliSecond: Word;
  568. begin
  569. if DateTime < UnixEpoch then
  570. raise EDateOutOfRange.Create(DateTime);
  571. DecodeDate(DateTime, Year, Month, Day);
  572. DecodeTime(DateTime, Hour, Minute, Second, MilliSecond);
  573. ATime.tm_isdst:= -1;
  574. ATime.tm_year:= Year - 1900;
  575. ATime.tm_mon:= Month - 1;
  576. ATime.tm_mday:= Day;
  577. ATime.tm_hour:= Hour;
  578. ATime.tm_min:= Minute;
  579. ATime.tm_sec:= Second;
  580. AUnixTime:= fpMkTime(@ATime);
  581. if (AUnixTime = -1) then
  582. Result:= TFileTimeExNull
  583. else begin
  584. Result:= TFileTimeEx.Create(AUnixTime, MilliSecond * 1000 * 1000);
  585. end;
  586. end;
  587. {$ELSE}
  588. var
  589. WinFileTime: TWinFileTime;
  590. begin
  591. WinFileTime:= DateTimeToWinFileTime(DateTime);
  592. Result:= WinFileTimeToUnixTime(WinFileTime);
  593. end;
  594. {$ENDIF}
  595. function UnixFileTimeToFileTime(UnixTime: TUnixFileTime): DCBasicTypes.TFileTime; inline;
  596. begin
  597. {$IF DEFINED(MSWINDOWS)}
  598. Result:= UnixFileTimeToWinTime(UnixTime);
  599. {$ELSE}
  600. Result:= UnixTime;
  601. {$ENDIF}
  602. end;
  603. function UnixFileTimeToDosTime(UnixTime: TUnixFileTime): TDosFileTime;
  604. begin
  605. Result := DateTimeToDosFileTime(UnixFileTimeToDateTime(UnixTime));
  606. end;
  607. function DosTimeToUnixFileTime(DosTime: TDosFileTime): TUnixFileTime;
  608. begin
  609. Result:= DateTimeToUnixFileTime(DosFileTimeToDateTime(DosTime));
  610. end;
  611. function UnixFileTimeToWinTime(UnixTime: TUnixFileTime): TWinFileTime;
  612. var
  613. WinFileTime: TWinFileTime;
  614. begin
  615. WinFileTime := UnixWinEpoch;
  616. if not AdjustWinFileTime(WinFileTime, Result, 10000000 * Int64(UnixTime)) then
  617. Result := WinFileTime;
  618. end;
  619. function WinFileTimeToUnixTime(WinTime: TWinFileTime): TUnixFileTime;
  620. begin
  621. if (WinTime < UnixWinEpoch) then
  622. Result:= 0
  623. else
  624. Result:= TUnixFileTime((WinTime - UnixWinEpoch) div 10000000);
  625. end;
  626. function WinFileTimeToDosTime(FileTime: TWinFileTime): TDosFileTime;
  627. begin
  628. Result := DateTimeToDosFileTime(WinFileTimeToDateTime(FileTime));
  629. end;
  630. function DosTimeToWinFileTime(FileTime: TDosFileTime): TWinFileTime;
  631. begin
  632. Result := DateTimeToWinFileTime(DosFileTimeToDateTime(FileTime));
  633. end;
  634. function WcxFileTimeToFileTime(WcxTime: LongInt): DCBasicTypes.TFileTime;
  635. begin
  636. {$IF DEFINED(MSWINDOWS)}
  637. DosToWinTime(TDosFileTime(WcxTime), Result);
  638. {$ELSE}
  639. Result := TFileTime(WcxTime);
  640. {$ENDIF}
  641. end;
  642. function FileTimeToWcxFileTime(FileTime: DCBasicTypes.TFileTime): LongInt;
  643. begin
  644. {$IF DEFINED(MSWINDOWS)}
  645. WinToDosTime(FileTime, Result);
  646. {$ELSE}
  647. Result := LongInt(FileTime);
  648. {$ENDIF}
  649. end;
  650. function WcxFileTimeToDateTime(WcxTime: LongInt): TDateTime;
  651. begin
  652. {$IF DEFINED(MSWINDOWS)}
  653. Result := DosFileTimeToDateTime(WcxTime);
  654. {$ELSEIF DEFINED(UNIX)}
  655. {$PUSH}{$R-}
  656. Result := FileTimeToDateTime(WcxTime);
  657. {$POP}
  658. {$ELSE}
  659. Result := 0;
  660. {$ENDIF}
  661. end;
  662. function UnixFileTimeToWcxTime(UnixTime: TUnixFileTime): LongInt;
  663. begin
  664. {$IF DEFINED(MSWINDOWS)}
  665. Result := UnixFileTimeToDosTime(UnixTime);
  666. {$ELSEIF DEFINED(UNIX)}
  667. {$PUSH}{$R-}
  668. Result := UnixTime;
  669. {$POP}
  670. {$ELSE}
  671. Result := 0;
  672. {$ENDIF}
  673. end;
  674. function GetTimeZoneBias: LongInt;
  675. begin
  676. {$IF DEFINED(MSWINDOWS)}
  677. Result := WinTimeZoneBias;
  678. {$ELSEIF DEFINED(UNIX)}
  679. Result := -Tzseconds div 60;
  680. {$ELSE}
  681. Result := 0;
  682. {$ENDIF}
  683. end;
  684. function MonthToNumberDef(const ShortMonthName: String; Default: Word): Word;
  685. var
  686. I: Word;
  687. begin
  688. Result:= Default;
  689. if ShortMonthName = EmptyStr then Exit;
  690. for I:= 1 to 12 do
  691. if SameText(ShortMonthName, ShortMonthNames[I]) then
  692. Exit(I);
  693. end;
  694. function YearShortToLong(Year: Word): Word;
  695. begin
  696. Result:= Year;
  697. if (Year < 100) then
  698. begin
  699. if (Year < 80) then
  700. Result:= Year + 2000
  701. else
  702. Result:= Year + 1900;
  703. end;
  704. end;
  705. function TwelveToTwentyFour(Hour: Word; Modifier: AnsiString): Word;
  706. begin
  707. Result:= Hour;
  708. if Length(Modifier) > 0 then
  709. begin
  710. case LowerCase(Modifier[1]) of
  711. 'a':
  712. begin
  713. if (Hour = 12) then
  714. Result:= 0;
  715. end;
  716. 'p':
  717. begin
  718. if (Hour < 12) then
  719. Result:= Hour + 12;
  720. end;
  721. end;
  722. end;
  723. end;
  724. function FileTimeCompare(SourceTime, TargetTime: TDateTime; NtfsShift: Boolean): Integer;
  725. const
  726. TimeDiff = 3100 / MSecsPerDay;
  727. NtfsDiff:TDateTime = (1/HoursPerDay);
  728. var
  729. FileTimeDiff,
  730. NtfsTimeDiff: TDateTime;
  731. begin
  732. FileTimeDiff:= SourceTime - TargetTime;
  733. if NtfsShift then
  734. begin
  735. NtfsTimeDiff:= FileTimeDiff - NtfsDiff;
  736. if (NtfsTimeDiff > -TimeDiff) and (NtfsTimeDiff < TimeDiff) then
  737. Exit(0);
  738. NtfsTimeDiff:= FileTimeDiff + NtfsDiff;
  739. if (NtfsTimeDiff > -TimeDiff) and (NtfsTimeDiff < TimeDiff) then
  740. Exit(0);
  741. end;
  742. if (FileTimeDiff > -TimeDiff) and (FileTimeDiff < TimeDiff) then
  743. Result:= 0
  744. else if FileTimeDiff > 0 then
  745. Result:= +1
  746. else if FileTimeDiff < 0 then
  747. Result:= -1;
  748. end;
  749. { EDateOutOfRange }
  750. constructor EDateOutOfRange.Create(ADateTime: TDateTime);
  751. begin
  752. inherited Create(EmptyStr);
  753. FDateTime := ADateTime;
  754. end;
  755. {$IF DEFINED(MSWINDOWS)}
  756. initialization
  757. WinTimeZoneBias := GetLocalTimeOffset;
  758. if (Win32MajorVersion > 5) then
  759. begin
  760. Pointer(TzSpecificLocalTimeToSystemTime):= GetProcAddress(GetModuleHandle(Kernel32),
  761. 'TzSpecificLocalTimeToSystemTime');
  762. end;
  763. {$ENDIF}
  764. end.