dcdatetimeutils.pas 22 KB

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