{**************************************************************************************************} { } { Project JEDI Code Library (JCL) } { } { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); } { you may not use this file except in compliance with the License. You may obtain a copy of the } { License at http://www.mozilla.org/MPL/ } { } { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF } { ANY KIND, either express or implied. See the License for the specific language governing rights } { and limitations under the License. } { } { The Original Code is JclDateTime.pas. } { } { The Initial Developers of the Original Code are documented in the accompanying help file } { JCLHELP.hlp. Portions created by these individuals are Copyright (C) of these individuals. } { } {**************************************************************************************************} { } { Routines for working with dates and times. Mostly conversion between the } { different formats but also some date testing routines (is leap year? etc) } { } { Unit Owner: Michael Schnell } { } {**************************************************************************************************} {**************************************************************************************************} { } { Modifications by MSchnell: } { 000622: } { } { Name changed GetCenturyOfDate -> CenturyOfDate } { } { Name changed GetCenturyBaseYear -> CenturyBaseYear } { } { function GetWeekNumber(Today: TDateTime): string; -> } { function ISOWeekNumber(DateTime: TDateTime; var YearOfWeekDay: Integer): Integer; } { } { Added overload function IsLeapYear(Year: Integer): Boolean; } { to avoid wrong results if the user thinks he calls SysUtils.IsLeapYear } { IsLeapYear is now using SysUtils.IsLeapYear } { } { Changed function DateTimeToSeconds(DateTime: TDateTime): extended; -> } { function TimeOfDateTimeToSeconds(DateTime: TDateTime): Integer; } { now not calling DecodeTime any more } { } { Added function TimeOfDateTimeToMSecs(DateTime: TDateTime): Integer } { } { 000624: } { DateTimeToDosDateTime performs the same action as SysUtils.DateTimeToFileDate } { so let's have Delphi do the work here } { DosDateTimeToDateTime performs the same action as SysUtils.FileDateToDateTime } { so let's have Delphi do the work here } { } { DosDateTimeToStr does not use FileTime any more } { } { Added function DateTimeToFileTime } { Added function LocalDateTimeToFileTime } { Changed function FileTimeToDateTime } { not using TSystemDate and avoid systemcalls } { Changed function FileTimeToLocalDateTime } { not using TSystemDate and avoid systemcalls } { } { 000625: } { Added function SystemTimeToFileTime } { Added function FieTimeToSystemTime } { Added function Datetimetosystemtime } { Added function DosDateTimeToFileTime } { Added function FileTimeToDosDateTime } { Added function SystemTimeToStr } { } { 000706: } { Formatted according to style rules } { } { 000708: } { Swapped function names CenturyOfDate and CenturyBaseYear } { those were obviously called wrong before } { Attention: must be done in the Help, too } { } { 000716: } { Support for negative dates and Year >= 10000 added for DecodeDate and EncodeDate } { } { 000809: } { added functions } { CreationDateTimeOfFile, LastAccessDateTimeOfFile and LastWriteDateTimeOfFile } { } { 000828: } { added function MakeYear4Digit } { } { 000907: } { added ISOWeekNumber with 1 and 3 parameters } { } { 000912: } { more elegant code for ISOWeekNumber } { added ISOWeekToDateTime } { added overload for ISOWeekNumber with three integer parameters } { } { 000914 } { added functions DayOfTheYear and DayOfTheYearToDateTime } { } { 000918 } { added function FormatDateTime } { } { 001015 } { avoiding "absolute" (in locations where stated) } { extended functionality for MakeYear4Digit: can pass Result unchanged if appropriate } { added function FATDatesEqual } { } { 001019 } { changed EasterSunday to the code by Marc Convents (marc.convents@progen.be) } { } { 010210 } { added overload procedures for compatibility: } { DateTimeToSystemTime, DosDateTimeToFileTime, FileTimeToDosDateTime, } { FileTimeToSystemTime, SystemTimeToFileTime } { } { } { TODO: } { Help for FATDatesEqual } { } { } { in Help: } { We do all conversions (but thoses provided by Delphi anyway) between } { TDatetime, TDosDateTime, TFileTime and TSystemTime plus } { TDatetime, TDosDateTime, TFileTime, TSystemTime to string } { } { } {**************************************************************************************************} // $Id: JclDateTime.pas,v 1.2 2004/04/14 21:55:07 druid Exp $ unit JclDateTime; {$I jcl.inc} {$IFDEF SUPPORTS_WEAKPACKAGEUNIT} {$WEAKPACKAGEUNIT ON} {$ENDIF SUPPORTS_WEAKPACKAGEUNIT} interface uses {$IFDEF MSWINDOWS} Windows, {$ENDIF MSWINDOWS} {$IFDEF LINUX} Types, {$ENDIF LINUX} SysUtils, JclBase, JclResources; { Encode / Decode functions } function EncodeDate(const Year: Integer; Month, Day: Word): TDateTime; procedure DecodeDate(Date: TDateTime; var Year, Month, Day: Word); overload; procedure DecodeDate(Date: TDateTime; var Year: Integer; var Month, Day: Word); overload; procedure DecodeDate(Date: TDateTime; var Year, Month, Day: Integer); overload; function CenturyOfDate(const DateTime: TDateTime): Integer; function CenturyBaseYear(const DateTime: TDateTime): Integer; function DayOfDate(const DateTime: TDateTime): Integer; function MonthOfDate(const DateTime: TDateTime): Integer; function YearOfDate(const DateTime: TDateTime): Integer; function DayOfTheYear(const DateTime: TDateTime; var Year: Integer): Integer; overload; function DayOfTheYear(const DateTime: TDateTime): Integer; overload; function DayOfTheYearToDateTime(const Year, Day: Integer): TDateTime; function HourOfTime(const DateTime: TDateTime): Integer; function MinuteOfTime(const DateTime: TDateTime): Integer; function SecondOfTime(const DateTime: TDateTime): Integer; { ISO 8601 support } function ISOWeekNumber(DateTime: TDateTime; var YearOfWeekNumber, WeekDay: Integer): Integer; overload; function ISOWeekNumber(DateTime: TDateTime; var YearOfWeekNumber: Integer): Integer; overload; function ISOWeekNumber(DateTime: TDateTime): Integer; overload; function ISOWeekToDateTime(const Year, Week, Day: Integer): TDateTime; { Miscellanous } function IsLeapYear(const Year: Integer): Boolean; overload; function IsLeapYear(const DateTime: TDateTime): Boolean; overload; function DaysInMonth(const DateTime: TDateTime): Integer; function Make4DigitYear(Year, Pivot: Integer): Integer; function MakeYear4Digit(Year, WindowsillYear: Integer): Integer; function EasterSunday(const Year: Integer): TDateTime; function FormatDateTime(Form: string; DateTime: TDateTime): string; function FATDatesEqual(const FileTime1, FileTime2: Int64): Boolean; overload; function FATDatesEqual(const FileTime1, FileTime2: TFileTime): Boolean; overload; //-------------------------------------------------------------------------------------------------- // Conversion //-------------------------------------------------------------------------------------------------- type TDosDateTime = Integer; function HoursToMSecs(Hours: Integer): Integer; function MinutesToMSecs(Minutes: Integer): Integer; function SecondsToMSecs(Seconds: Integer): Integer; function TimeOfDateTimeToSeconds(DateTime: TDateTime): Integer; function TimeOfDateTimeToMSecs(DateTime: TDateTime): Integer; {$IFDEF MSWINDOWS} function DateTimeToLocalDateTime(DateTime: TDateTime): TDateTime; function DateTimeToDosDateTime(const DateTime: TDateTime): TDosDateTime; function DateTimeToFileTime(DateTime: TDateTime): TFileTime; function DateTimeToSystemTime(DateTime: TDateTime): TSystemTime; overload; procedure DateTimeToSystemTime(DateTime: TDateTime; var SysTime : TSystemTime); overload; function LocalDateTimeToFileTime(DateTime: TDateTime): FileTime; function LocalDateTimeToDateTime(DateTime: TDateTime): TDateTime; {$ENDIF MSWINDOWS} function DosDateTimeToDateTime(const DosTime: TDosDateTime): TDateTime; {$IFDEF MSWINDOWS} function DosDateTimeToFileTime(DosTime: TDosDateTime): TFileTime; overload; procedure DosDateTimeToFileTime(DTH, DTL: Word; FT: TFileTime); overload; function DosDateTimeToSystemTime(const DosTime: TDosDateTime): TSystemTime; {$ENDIF MSWINDOWS} function DosDateTimeToStr(DateTime: Integer): string; function FileTimeToDateTime(const FileTime: TFileTime): TDateTime; {$IFDEF MSWINDOWS} function FileTimeToLocalDateTime(const FileTime: TFileTime): TDateTime; function FileTimeToDosDateTime(const FileTime: TFileTime): TDosDateTime; overload; procedure FileTimeToDosDateTime(const FileTime: TFileTime; var Date, Time: Word); overload; function FileTimeToSystemTime(const FileTime: TFileTime): TSystemTime; overload; procedure FileTimeToSystemTime(const FileTime: TFileTime; var ST: TSystemTime); overload; {$ENDIF MSWINDOWS} function FileTimeToStr(const FileTime: TFileTime): string; {$IFDEF MSWINDOWS} function SystemTimeToDosDateTime(const SystemTime: TSystemTime): TDosDateTime; function SystemTimeToFileTime(const SystemTime: TSystemTime): TFileTime; overload; procedure SystemTimeToFileTime(const SystemTime: TSystemTime; FTime : TFileTime); overload; function SystemTimeToStr(const SystemTime: TSystemTime): string; //-------------------------------------------------------------------------------------------------- // Filedates //-------------------------------------------------------------------------------------------------- function CreationDateTimeOfFile(const Sr: TSearchRec): TDateTime; function LastAccessDateTimeOfFile(const Sr: TSearchRec): TDateTime; function LastWriteDateTimeOfFile(const Sr: TSearchRec): TDateTime; {$ENDIF MSWINDOWS} type EJclDateTimeError = class(EJclError); implementation const DaysInMonths: array [1..12] of Integer = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); MinutesPerDay = 60 * 24; SecondsPerDay = MinutesPerDay * 60; MsecsPerMinute = 60 * 1000; MsecsPerHour = 60 * MsecsPerMinute; DaysPerYear = 365.2422454; // Solar Year DaysPerMonth = DaysPerYear / 12; DateTimeBaseDay = -693593; // 1/1/0001 EncodeDateMaxYear = 9999; SolarDifference = 1.7882454; // Difference of Julian Calendar to Solar Calendar at 1/1/10000 DateTimeMaxDay = 2958466; // 12/31/EncodeDateMaxYear + 1; FileTimeBase = -109205.0; FileTimeStep: Extended = 24.0 * 60.0 * 60.0 * 1000.0 * 1000.0 * 10.0; // 100 nSek per Day // Weekday to start the week // 1 : Sonday // 2 : Monday (according to ISO 8601) ISOFirstWeekDay = 2; // minmimum number of days of the year in the first week of the year week // 1 : week one starts at 1/1 // 4 : first week has at least four days (according to ISO 8601) // 7 : first full week ISOFirstWeekMinDays = 4; //-------------------------------------------------------------------------------------------------- function EncodeDate(const Year: Integer; Month, Day: Word): TDateTime; overload; begin if (Year > 0) and (Year < EncodeDateMaxYear+1) then Result := SysUtils.EncodeDate(Year, Month, Day) else begin if Year <= 0 then Result := Year * DaysPerYear + DateTimeBaseDay else // Year >= 10000 // for some reason year 0 does not exist so we switch from // the last day of year -1 (-693594) to the first days of year 1 Result := (Year-1) * DaysPerYear + DateTimeBaseDay // BaseDate is 1/1/1 + SolarDifference; // guarantee a smooth transition at 1/1/10000 Result := Trunc(Result); Result := Result + (Month-1) * DaysPerMonth; Result := Round(Result) + (Day-1); end; end; //-------------------------------------------------------------------------------------------------- procedure DecodeDate(Date: TDateTime; var Year, Month, Day: Word); begin SysUtils.DecodeDate(Date, Year, Month, Day); end; //-------------------------------------------------------------------------------------------------- procedure DecodeDate(Date: TDateTime; var Year, Month, Day: Integer); var WMonth, WDay: Word; begin DecodeDate(Date, Year, WMonth, WDay); Month := Wmonth; Day := WDay; end; //-------------------------------------------------------------------------------------------------- procedure DecodeDate(Date: TDateTime; var Year: Integer; var Month, Day: Word); var WYear: Word; RDays, RMonths: TDateTime; begin if (Date >= DateTimeBaseDay) and (Date < DateTimeMaxDay) then begin SysUtils.DecodeDate(Date, WYear, Month, Day); Year := WYear; end else begin Year := Trunc((Date - DateTimeBaseDay) / DaysPerYear); if Year <= 0 then Year := Year - 1 // for some historical reason year 0 does not exist so we switch from // the last day of year -1 (-693594) to the first days of year 1 else // Year >= 10000 Date := Date - SolarDifference; // guarantee a smooth transition at 1/1/10000 RDays := Date - DateTimeBaseDay; // Days relative to 1/1/0001 RMonths := RDays / DaysPerMonth; // "Months" relative to 1/1/0001 RMonths := RMonths - Year * 12.0; // 12 "Months" per Year if RMonths < 0 then // possible truncation glitches begin RMonths := 11; Year := Year - 1; end; Month := Trunc(RMonths); Rmonths := Month; Month := Month + 1; RDays := RDays - Year * DaysPerYear; // subtract Base Day ot the year RDays := RDays - RMonths * DaysPerMonth;// subtract Base Day of the month Day := Trunc (RDays)+ 1; if Year > 0 then // Year >= 10000 Year := Year + 1; // BaseDate is 1/1/1 end; end; //-------------------------------------------------------------------------------------------------- procedure ResultCheck(Val: LongBool); begin if not Val then raise EJclDateTimeError.Create(RsDateConversion); end; //-------------------------------------------------------------------------------------------------- function CenturyBaseYear(const DateTime: TDateTime): Integer; var Y: Integer; begin Y := YearOfDate(DateTime); Result := (Y div 100) * 100; if Y <= 0 then Result := Result - 100; end; //-------------------------------------------------------------------------------------------------- function CenturyOfDate(const DateTime: TDateTime): Integer; var Y: Integer; begin Y := YearOfDate(DateTime); if Y > 0 then Result := (Y div 100) + 1 else Result := (Y div 100) - 1; end; //-------------------------------------------------------------------------------------------------- function DayOfDate(const DateTime: TDateTime): Integer; var Y: Integer; M, D: Word; begin DecodeDate(DateTime, Y, M, D); Result := D; end; //-------------------------------------------------------------------------------------------------- function MonthOfDate(const DateTime: TDateTime): Integer; var Y: Integer; M, D: Word; begin DecodeDate(DateTime, Y, M, D); Result := M; end; //-------------------------------------------------------------------------------------------------- function YearOfDate(const DateTime: TDateTime): Integer; var M, D: Word; begin DecodeDate(DateTime, Result, M, D); end; //-------------------------------------------------------------------------------------------------- function DayOfTheYear(const DateTime: TDateTime; var Year: Integer): Integer; var Month, Day: Word; DT: TDateTime; begin DecodeDate(DateTime, Year, Month, Day); DT := EncodeDate(Year, 1, 1); Result := Trunc(DateTime); Result := Result - Trunc(DT) + 1; end; //-------------------------------------------------------------------------------------------------- function DayOfTheYear(const DateTime: TDateTime): Integer; var Year: Integer; begin Result := DayOfTheYear(DateTime, Year); end; //-------------------------------------------------------------------------------------------------- function DayOfTheYearToDateTime(const Year, Day: Integer): TDateTime; begin Result := EncodeDate(Year, 1, 1) + Day - 1; end; //-------------------------------------------------------------------------------------------------- function HourOfTime(const DateTime: TDateTime): Integer; var H, M, S, MS: Word; begin DecodeTime(DateTime, H, M, S, MS); Result := H; end; //-------------------------------------------------------------------------------------------------- function MinuteOfTime(const DateTime: TDateTime): Integer; var H, M, S, MS: Word; begin DecodeTime(DateTime, H, M, S, MS); Result := M; end; //-------------------------------------------------------------------------------------------------- function SecondOfTime(const DateTime: TDateTime): Integer; var H, M, S, MS: Word; begin DecodeTime(DateTime, H, M, S, MS); Result := S; end; //-------------------------------------------------------------------------------------------------- function TimeOfDateTimeToSeconds(DateTime: TDateTime): Integer; begin Result := Round(Frac(DateTime) * SecondsPerDay); end; //-------------------------------------------------------------------------------------------------- function TimeOfDateTimeToMSecs(DateTime: TDateTime): Integer; begin Result := Round(Frac(DateTime) * MSecsPerDay); end; //-------------------------------------------------------------------------------------------------- function DaysInMonth(const DateTime: TDateTime): Integer; var M: Integer; begin M := MonthOfDate(DateTime); Result := DaysInMonths[M]; if (M = 2) and IsLeapYear(DateTime) then Result := 29; end; //-------------------------------------------------------------------------------------------------- // DayOfWeek function returns integer 1..7 equivalent to Sunday..Saturday. // ISO 8601 weeks start with Monday and the first week of a year is the one which // includes the first Thursday function ISOWeekNumber(DateTime: TDateTime; var YearOfWeekNumber, WeekDay: Integer): Integer; var Month, Day: Word; begin WeekDay := ((DayOfWeek(DateTime) - ISOFirstWeekDay + 7) mod 7) + 1; DateTime := DateTime - WeekDay + 8 - ISOFirstWeekMinDays; DecodeDate(DateTime, YearOfWeekNumber, Month, Day); Result := (Trunc(DateTime - EncodeDate(YearOfWeekNumber, 1, 1)) div 7) + 1; end; //-------------------------------------------------------------------------------------------------- function ISOWeekNumber(DateTime: TDateTime; var YearOfWeekNumber: Integer): Integer; var Dummy: Integer; begin Result := ISOWeekNumber(DateTime, YearOfWeekNumber, Dummy); end; //-------------------------------------------------------------------------------------------------- function ISOWeekNumber(DateTime: TDateTime): Integer; var Dummy1, Dummy2: Integer; begin Result := ISOWeekNumber(DateTime, Dummy1, Dummy2); end; //-------------------------------------------------------------------------------------------------- function ISOWeekToDateTime(const Year, Week, Day: Integer): TDateTime; begin Result := EncodeDate(Year, 1, ISOFirstWeekMinDays); Result := Result + (Week - 1) * 7 - ((DayOfWeek(Result) + (7 - ISOFirstWeekDay)) mod 7) + Day - 1; end; //-------------------------------------------------------------------------------------------------- // The original Gregorian rule for all who want to learn it // Result := (Year mod 4 = 0) and ((Year mod 100 <> 0) or (Year mod 400 = 0)); function IsLeapYear(const Year: Integer): Boolean; begin Result := SysUtils.IsLeapYear(Year); end; //-------------------------------------------------------------------------------------------------- function IsLeapYear(const DateTime: TDateTime): Boolean; begin Result := IsLeapYear(YearOfDate(DateTime)); end; //-------------------------------------------------------------------------------------------------- function Make4DigitYear(Year, Pivot: Integer): Integer; begin // TODO Assert((Year >= 0) and (Year <= 100) and (Pivot >= 0) and (Pivot <= 100)); if Year = 100 then Year := 0; if Pivot = 100 then Pivot := 0; if Year < Pivot then Result := 2000 + Year else Result := 1900 + Year; end; //-------------------------------------------------------------------------------------------------- // "window" technique for years to translate 2 digits to 4 digits. // The window is 100 years wide // The windowsill year is the lower edge of the window // A windowsill year of 1900 is equivalent to putting 1900 before every 2-digit year // if WindowsillYear is 1940, then 40 is interpreted as 1940, 00 as 2000 and 39 as 2039 // The system default is 1950 function MakeYear4Digit(Year, WindowsillYear: Integer): Integer; var CC, Y: Integer; begin // have come across this specific problem : y2K read as year 100 if Year = 100 then Year := 0; // turn 2 digit years to 4 digits Y := Year mod 100; CC := (WindowsillYear div 100) * 100; Result := Y + CC; // give the result the same century as the windowsill if Result < WindowsillYear then // cannot be lower than the windowsill Result := Result + 100; if (Year >= 100) or (Year < 0) then Assert(Year = Result); // Assert: no unwanted century translation end; //-------------------------------------------------------------------------------------------------- // Calculates and returns Easter Day for specified year. // Originally from Mark Lussier, AppVision <MLussier@best.com>. // Corrected to prevent integer overflow if it is inadvertedly // passed a year of 6554 or greater. function EasterSunday(const Year: Integer): TDateTime; var Month, Day, Moon, Epact, Sunday, Gold, Cent, Corx, Corz: Integer; begin { The Golden Number of the year in the 19 year Metonic Cycle: } Gold := (Year mod 19) + 1; { Calculate the Century: } Cent := (Year div 100) + 1; { Number of years in which leap year was dropped in order... } { to keep in step with the sun: } Corx := (3 * Cent) div 4 - 12; { Special correction to syncronize Easter with moon's orbit: } Corz := (8 * Cent + 5) div 25 - 5; { Find Sunday: } Sunday := (Longint(5) * Year) div 4 - Corx - 10; { ^ To prevent overflow at year 6554} { Set Epact - specifies occurrence of full moon: } Epact := (11 * Gold + 20 + Corz - Corx) mod 30; if Epact < 0 then Epact := Epact + 30; if ((Epact = 25) and (Gold > 11)) or (Epact = 24) then Epact := Epact + 1; { Find Full Moon: } Moon := 44 - Epact; if Moon < 21 then Moon := Moon + 30; { Advance to Sunday: } Moon := Moon + 7 - ((Sunday + Moon) mod 7); if Moon > 31 then begin Month := 4; Day := Moon - 31; end else begin Month := 3; Day := Moon; end; Result := EncodeDate(Year, Month, Day); end; //================================================================================================== // Conversion //================================================================================================== {$IFDEF MSWINDOWS} function DateTimeToLocalDateTime(DateTime: TDateTime): TDateTime; var TimeZoneInfo: TTimeZoneInformation; begin FillChar(TimeZoneInfo, SizeOf(TimeZoneInfo), #0); case GetTimeZoneInformation(TimeZoneInfo) of TIME_ZONE_ID_STANDARD, TIME_ZONE_ID_UNKNOWN: Result := DateTime + (TimeZoneInfo.Bias / MinutesPerDay); TIME_ZONE_ID_DAYLIGHT: Result := DateTime - ((TimeZoneInfo.Bias + TimeZoneInfo.DaylightBias) / MinutesPerDay); else raise EJclDateTimeError.Create(RsMakeUTCTime); end; end; //-------------------------------------------------------------------------------------------------- function LocalDateTimeToDateTime(DateTime: TDateTime): TDateTime; var TimeZoneInfo: TTimeZoneInformation; begin FillChar(TimeZoneInfo, SizeOf(TimeZoneInfo), #0); case GetTimeZoneInformation(TimeZoneInfo) of TIME_ZONE_ID_STANDARD, TIME_ZONE_ID_UNKNOWN: Result := DateTime + (TimeZoneInfo.Bias / MinutesPerDay); TIME_ZONE_ID_DAYLIGHT: Result := DateTime + ((TimeZoneInfo.Bias + TimeZoneInfo.DaylightBias) / MinutesPerDay); else raise EJclDateTimeError.Create(RsMakeUTCTime); end; end; {$ENDIF MSWINDOWS} //-------------------------------------------------------------------------------------------------- function HoursToMSecs(Hours: Integer): Integer; begin Assert(Hours < MaxInt / MsecsPerHour); Result := Hours * MsecsPerHour; end; //-------------------------------------------------------------------------------------------------- function MinutesToMSecs(Minutes: Integer): Integer; begin Assert(Minutes < MaxInt / MsecsPerMinute); Result := Minutes * MsecsPerMinute; end; //-------------------------------------------------------------------------------------------------- function SecondsToMSecs(Seconds: Integer): Integer; begin Assert(Seconds < MaxInt / 1000); Result := Seconds * 1000; end; //-------------------------------------------------------------------------------------------------- // using system calls this can be done like this: // var // SystemTime: TSystemTime; // begin // ResultCheck(FileTimeToSystemTime(FileTime, SystemTime)); // Result := SystemTimeToDateTime(SystemTime); function FileTimeToDateTime(const FileTime: TFileTime): TDateTime; begin Result := Int64(FileTime) / FileTimeStep; Result := Result + FileTimeBase; end; //-------------------------------------------------------------------------------------------------- {$IFDEF MSWINDOWS} function FileTimeToLocalDateTime(const FileTime: TFileTime): TDateTime; var LocalFileTime: TFileTime; begin ResultCheck(FileTimeToLocalFileTime(FileTime, LocalFileTime)); Result := FileTimeToDateTime(LocalFileTime); end; //-------------------------------------------------------------------------------------------------- function LocalDateTimeToFileTime(DateTime: TDateTime): FileTime; var LocalFileTime: TFileTime; begin LocalFileTime := DateTimeToFileTime(DateTime); ResultCheck(LocalFileTimeToFileTime(LocalFileTime, Result)); end; {$ENDIF MSWINDOWS} //-------------------------------------------------------------------------------------------------- function DateTimeToFileTime(DateTime: TDateTime): TFileTime; var E: Extended; F64: Int64; begin E := (DateTime - FileTimeBase) * FileTimeStep; F64 := Round(E); Result := TFileTime(F64); end; //-------------------------------------------------------------------------------------------------- {$IFDEF MSWINDOWS} function DosDateTimeToSystemTime(const DosTime: TDosDateTime): TSystemTime; var FileTime: TFileTime; begin FileTime := DosDateTimeToFileTime(DosTime); Result := FileTimeToSystemTime(FileTime); end; //-------------------------------------------------------------------------------------------------- function SystemTimeToDosDateTime(const SystemTime: TSystemTime): TDosDateTime; var FileTime: TFileTime; begin FileTime := SystemTimeToFileTime(SystemTime); Result := FileTimeToDosDateTime(FileTime); end; {$ENDIF MSWINDOWS} //-------------------------------------------------------------------------------------------------- // DosDateTimeToDateTime performs the same action as SysUtils.FileDateToDateTime // not using SysUtils.FileDateToDateTime this can be done like that: // var // FileTime: TFileTime; // SystemTime: TSystemTime; // begin // ResultCheck(DosDateTimeToFileTime(HiWord(DosTime), LoWord(DosTime), FileTime)); // ResultCheck(FileTimeToSystemTime(FileTime, SystemTime)); // Result := SystemTimeToDateTime(SystemTime); function DosDateTimeToDateTime(const DosTime: TDosDateTime): TDateTime; begin Result := SysUtils.FileDateToDateTime(DosTime); end; //-------------------------------------------------------------------------------------------------- // DateTimeToDosDateTime performs the same action as SysUtils.DateTimeToFileDate // not using SysUtils.DateTimeToDosDateTime this can be done like that: // var // SystemTime: TSystemTime; // FileTime: TFileTime; // Date, Time: Word; // begin // DateTimeToSystemTime(DateTime, SystemTime); // ResultCheck(SystemTimeToFileTime(SystemTime, FileTime)); // ResultCheck(FileTimeToDosDateTime(FileTime, Date, Time)); // Result := (Date shl 16) or Time; function DateTimeToDosDateTime(const DateTime: TDateTime): TDosDateTime; begin Result := SysUtils.DateTimeToFileDate(DateTime); end; //-------------------------------------------------------------------------------------------------- {$IFDEF MSWINDOWS} function FileTimeToSystemTime(const FileTime: TFileTime): TSystemTime; overload; begin ResultCheck(Windows.FileTimeToSystemTime(FileTime, Result)); end; //-------------------------------------------------------------------------------------------------- procedure FileTimeToSystemTime(const FileTime: TFileTime; var ST: TSystemTime); overload; begin Windows.FileTimeToSystemTime(FileTime, ST); end; //-------------------------------------------------------------------------------------------------- function SystemTimeToFileTime(const SystemTime: TSystemTime): TFileTime; overload; begin ResultCheck(Windows.SystemTimeToFileTime(SystemTime, Result)); end; //-------------------------------------------------------------------------------------------------- procedure SystemTimeToFileTime(const SystemTime: TSystemTime; FTime: TFileTime); overload; begin Windows.SystemTimeToFileTime(SystemTime, FTime); end; //-------------------------------------------------------------------------------------------------- function DateTimeToSystemTime(DateTime: TDateTime): TSystemTime; overload; begin SysUtils.DateTimeToSystemTime(DateTime, Result); end; //-------------------------------------------------------------------------------------------------- procedure DateTimeToSystemTime(DateTime: TDateTime; var SysTime : TSystemTime); overload; begin SysUtils.DateTimeToSystemTime(DateTime, SysTime); end; //-------------------------------------------------------------------------------------------------- function DosDateTimeToFileTime(DosTime: TDosDateTime): TFileTime; overload; begin ResultCheck(Windows.DosDateTimeToFileTime(HiWord(DosTime), LoWord(DosTime), Result)); end; //-------------------------------------------------------------------------------------------------- procedure DosDateTimeToFileTime(DTH, DTL: Word; FT: TFileTime); overload; begin Windows.DosDateTimeToFileTime(DTH, DTL, FT); end; //-------------------------------------------------------------------------------------------------- function FileTimeToDosDateTime(const FileTime: TFileTime): TDosDateTime; overload; var Date, Time: Word; begin ResultCheck(Windows.FileTimeToDosDateTime(FileTime, Date, Time)); Result := (Date shl 16) or Time; end; //-------------------------------------------------------------------------------------------------- procedure FileTimeToDosDateTime(const FileTime: TFileTime; var Date, Time: Word); overload; begin Windows.FileTimeToDosDateTime(FileTime, Date, Time); end; {$ENDIF MSWINDOWS} //-------------------------------------------------------------------------------------------------- function FileTimeToStr(const FileTime: TFileTime): string; var DateTime: TDateTime; begin DateTime := FileTimeToDateTime(FileTime); Result := DateTimeToStr(DateTime); end; //-------------------------------------------------------------------------------------------------- function DosDateTimeToStr(DateTime: Integer): string; begin Result := DateTimeToStr(DosDateTimeToDateTime(DateTime)); end; //-------------------------------------------------------------------------------------------------- {$IFDEF MSWINDOWS} // we can't do this better without copying Borland-owned code from the Delphi VCL, // as the straight forward conversion doing exactly this task is hidden // deeply inside SysUtils.pas. // So the date is converted forth and back to/from Julian date // If someone needs a faster version please take a look at SysUtils.pas->DateTimeToStr. function SystemTimeToStr(const SystemTime: TSystemTime): string; begin Result := DateTimeToStr(SystemTimeToDateTime(SystemTime)); end; //-------------------------------------------------------------------------------------------------- function CreationDateTimeOfFile(const Sr: TSearchRec): TDateTime; begin Result := FileTimeToDateTime(Sr.FindData.ftCreationTime); end; //-------------------------------------------------------------------------------------------------- function LastAccessDateTimeOfFile(const Sr: TSearchRec): TDateTime; begin Result := FileTimeToDateTime(Sr.FindData.ftLastAccessTime); end; //-------------------------------------------------------------------------------------------------- function LastWriteDateTimeOfFile(const Sr: TSearchRec): TDateTime; begin Result := FileTimeToDateTime(Sr.FindData.ftLastWriteTime); end; {$ENDIF MSWINDOWS} //-------------------------------------------------------------------------------------------------- // Additional format tokens (also available in upper case): // w: Week no according to ISO // ww: Week no according to ISO forced two digits // i: Year of the ISO-week denoted by w (4 digits for 1000..9999) // ii: Year of the ISO-week denoted by w forced two digits // e: Number of the Day in the ISO-week denoted by w (ISO-Notation 1=Monday...) // f: Number of the Day in the year denoted by y // fff: Number of the Day in the year denoted by y forced three digits function FormatDateTime(Form: string; DateTime: TDateTime): string; var N: Integer; ISODay, ISOWeek, ISOYear, DayOfYear, YY: Integer; procedure Digest; begin if N > 1 then begin Result := Result + Copy(Form, 1, N - 1); System.Delete(Form, 1, N - 1); N := 1; end; end; begin ISOWeek := 0; DayOfYear := 0; Result := ''; N := 1; while N <= Length(Form) do begin case Form[N] of '"': begin Inc(N); Digest; N := Pos('"', Form); if N = 0 then begin Result := Result + Form; Form := ''; N := 1; end else begin Inc(N); Digest; end; end; '''': begin Inc(N); Digest; N := Pos('''', Form); if N = 0 then begin Result := Result + Form; Form := ''; N := 1; end else begin Inc(N); Digest; end; end; 'i', 'I': //ISO Week Year begin Digest; if ISOWeek = 0 then ISOWeek := ISOWeekNumber(DateTime, ISOYear, ISoDay); if (Length(Form) > 1) and ((Form[2] = 'i') or (Form[2] = 'I')) then begin // <ii> if (Length(Form) > 2) and ((Form[3] = 'i') or (Form[3] = 'I')) then begin if (Length(Form) > 3) and ((Form[4] = 'i') or (Form[4] = 'I')) then begin // <iiii> Delete(Form, 1, 4); Result := Result + '"' + IntToStr(ISOYear) + '"'; end else begin // <iii> Delete(Form, 1, 3); Result := Result + '"' + IntToStr(ISOYear) + '"'; end; end else begin // <ii> Delete(Form, 1, 2); Result := Result + '"'; if ISOYear < 10 then Result := Result + '0'; YY := ISOYear mod 100; if YY < 10 then Result := Result + '0'; Result := Result + IntToStr(YY) + '"'; end; end else begin // <i> Delete(Form, 1, 1); Result := Result + '"' + IntToStr(ISOYear) + '"'; end; end; 'w', 'W': // ISO Week begin Digest; if ISOWeek = 0 then ISOWeek := ISOWeekNumber(DateTime, ISOYear, ISoDay); if (Length(Form) > 1) and ((Form[2] = 'w') or (Form[2] = 'W')) then begin // <ww> Delete(Form, 1, 2); Result := Result + '"'; if ISOWeek < 10 then Result := Result + '0'; Result := Result + IntToStr(ISOWeek) + '"'; end else begin // <w> Delete(Form, 1, 1); Result := Result + '"' + IntToStr(ISOWeek) + '"'; end; end; 'e', 'E': // ISO Week Day begin Digest; if ISOWeek = 0 then ISOWeek := ISOWeekNumber(DateTime, ISOYear, ISODay); Delete(Form, 1, 1); Result := Result + '"' + IntToStr(ISODay) + '"'; end; 'f', 'F': // Day of the Year begin Digest; if DayOfYear = 0 then DayOfYear := DayOfTheYear(DateTime); if (Length(Form) > 1) and ((Form[2] = 'f') or (Form[2] = 'F')) then begin if (Length(Form) > 2) and ((Form[3] = 'f') or (Form[3] = 'F')) then begin // <fff> Delete(Form, 1, 3); Result := Result + '"'; if DayOfYear < 10 then Result := Result + '0'; if DayOfYear < 100 then Result := Result + '0'; Result := Result + IntToStr(DayOfYear) + '"'; end else begin // <ff> Delete(Form, 1, 2); Result := Result + '"'; if DayOfYear < 10 then Result := Result + '0'; Result := Result + IntToStr(DayOfYear) + '"'; end; end else begin // <f> Delete(Form, 1, 1); Result := Result + '"' + IntToStr(DayOfYear) + '"'; end end; else Inc(N); end; end; Result := SysUtils.FormatDateTime(Result + Form, DateTime); end; //-------------------------------------------------------------------------------------------------- // FAT has a granularity of 2 seconds // The intervals are 1/10 of a second function FATDatesEqual(const FileTime1, FileTime2: Int64): Boolean; const ALLOWED_FAT_FILE_TIME_VARIATION = 20; begin Result := Abs(FileTime1 - FileTime2) <= ALLOWED_FAT_FILE_TIME_VARIATION; end; //-------------------------------------------------------------------------------------------------- function FATDatesEqual(const FileTime1, FileTime2: TFileTime): Boolean; begin Result := FATDatesEqual(Int64(FileTime1), Int64(FileTime2)); end; end.