dcdatetimeutils.pas 24 KB

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