MiTec/Common/MiTeC_Datetime.pas
2024-07-06 22:30:25 +02:00

1019 lines
33 KiB
ObjectPascal
Raw Permalink Blame History

{*******************************************************}
{ MiTeC Common Routines }
{ Datetime routines }
{ }
{ }
{ Copyright (c) 1997-2021 Michal Mutl }
{ }
{*******************************************************}
{$INCLUDE Compilers.inc}
unit MiTeC_Datetime;
interface
uses {$IFDEF RAD9PLUS}
WinAPI.Windows, System.SysUtils, System.Classes;
{$ELSE}
Windows, SysUtils, Classes;
{$ENDIF}
{$IFDEF FPC}
type
TValueRelationship = -1..1;
const
LessThanValue = Low(TValueRelationship);
EqualsValue = 0;
GreaterThanValue = High(TValueRelationship);
{$ENDIF}
type
TLanguage = (lngEn, lngCz);
TRegistryTimeZoneInfo = record
Bias: Longint;
StandardBias: Longint;
DaylightBias: Longint;
StandardDate: TSystemTime;
DaylightDate: TSystemTime;
end;
const
DaysInMonths: array [1..12] of Integer =
(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
MinutesPerDay = 60 * 24;
SecondsPerMinute = 60;
SecondsPerHour = 3600;
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
tzAEST = 'AUS Eastern Standard Time';
tzJST = 'Tokyo Standard Time';
tzCET = 'Central Europe Standard Time';
tzGMT = 'GMT Standard Time';
tzEST = 'Eastern Standard Time';
tzPST = 'Pacific Standard Time';
procedure ResetMemory(out P; Size: Longint);
function SecondsToTime(const ASeconds: Int64): TDateTime;
function UTCToDateTime(UTC: Cardinal; ConvertTimeToLocal: Boolean = False): TDateTime;
function UTCToDateTimeEx(UTC: int64; CorrectToLocal: Boolean = True): TDateTime;
function Int64ToDateTime(UTC: Int64; ConvertTimeToLocal: Boolean = False): TDateTime;
function DSTDate2Date(dstDate: TSystemTime; year: word): TDateTime;
function FileTimeToDateTimeStr(FileTime: TFileTime): string;
function FileTimeToDateTime(FT: FILETIME; ConvertTimeToLocal: Boolean = False): TDateTime;
function ParseDate(YYYYMMDD: string): TDatetime;
function EasterSunday(const Year: Word): TDateTime;
function GetWorkDays(ADT: TDatetime; ACount: Integer): Integer;
function DateToStrDef(ADT: TDateTime; ADef: string = ''): string;
function DateTimeToStrDef(ADT: TDateTime; ADef: string = ''; AValidDateLimit: TDatetime = 0): string;
function DateTimeToFileTime(dt: TDateTime): FILETIME;
function IncWorkDays(ADT: TDateTime; ADays: Cardinal): TDateTime;
function DecWorkDays(ADT: TDateTime; ADays: Cardinal): TDateTime;
function UTCToSystemTime(UTC : TDateTime) : TDateTime;
function GetDaylightBias: Integer;
function GetDaylightName: string;
function GetCurrentTimezoneKeyName: string;
procedure GetTimeZoneList(AList: TStringList);
function GetTimeZone(AKeyName: string; out AData: TTimeZoneInformation; AYear: Word = 0): string;
function LocalDateTimeToTZ(AValue: TDateTime; ATZ: TTimeZoneInformation): TDateTime;
function GetDateTimeForBiasSystemTime(ADateTime: TSystemTime; AGivenYear: Integer): TDateTime;
function GetBiasForDate(ADateTime: TDateTime): Integer;
function LocalDateTimeToUTC(Local: TDateTime): TDateTime;
function UTCToLocalDateTime(UTC: TDateTime): TDateTime;
function RFC822DateToDateTime(RFC822DateTime: string; ADefault: TDatetime = 0): TDateTime;
function CompareSysTime(st1, st2: TSystemTime): integer;
function GreaterOrEquals(ANow,AThen: TDateTime): Boolean;
function LessOrEquals(ANow,AThen: TDateTime): Boolean;
function Less(ANow,AThen: TDateTime): Boolean;
function Greater(ANow,AThen: TDateTime): Boolean;
function IsTimeInRange(ATime: TDateTime; AStartTime, AEndTime: TDateTime; AInclusive: Boolean = True): Boolean;
function IsDateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
function IsDateInRange(ADate: TDateTime; AStartDate, AEndDate: TDateTime; AInclusive: Boolean = True): Boolean;
function SecondsBetweenSgn(ANow,AThen: TDateTime): Integer;
function MinutesBetweenSgn(ANow,AThen: TDateTime): Integer;
function HoursBetweenSgn(ANow,AThen: TDateTime): Integer;
function DaysBetweenSgn(ANow,AThen: TDateTime): Integer;
function WeeksBetweenSgn(ANow,AThen: TDateTime): Integer;
function FormatTicks(AValue :Int64; AWholeSecondsOnly: Boolean = True) :string;
function FormatSeconds(AValue :Int64; AShort: Boolean = True) :string;
function FormatMilliseconds(AValue :Int64; AWholeSecondsOnly: Boolean = True; AShort: Boolean = True) :string;
function XMLStrToDateTime(const AString: string): TDateTime;
function XMLStrToDateTimeDef(const AString: string; const ADefDateTime: TDateTime = 0): TDateTime;
function XMLTryStrToDateTime(const AString: string; var ADatetime: TDateTime): Boolean;
const
{$IFDEF CZLNG}
Zodiac :array[0..12] of record
Sign :string;
FromDOY, ToDOY :integer;
Ruler,Traits :string;
end = (
(Sign:'Aries - Beran';FromDOY:81;ToDOY:111;Ruler:'Mars';Traits:'State<74>nost, r<>znost a netrp<72>livost'),
(Sign:'Taurus - B<>k';FromDOY:112;ToDOY:142;Ruler:'Venu<6E>e';Traits:'Odhodlanost, v<>elost a tvrdohlavost'),
(Sign:'Gemini - Bl<42><6C>enci';FromDOY:143;ToDOY:173;Ruler:'Merkur';Traits:'<27>ilost, v<>estrannost a nest<73>lost'),
(Sign:'Cancer - Rak';FromDOY:174;ToDOY:204;Ruler:'Mes<65>c';Traits:'Vynal<61>zavost, citlivost a sebeovl<76>d<EFBFBD>n<EFBFBD>'),
(Sign:'Leo - Lev';FromDOY:205;ToDOY:235;Ruler:'Slunce';Traits:'S<>la, tv<74>r<EFBFBD><72> talent a sebev<65>dom<6F>'),
(Sign:'Virgo - Panna';FromDOY:236;ToDOY:266;Ruler:'Merkur';Traits:'Skromnost, prakti<74>nost a povznesenost'),
(Sign:'Libra - V<>hy';FromDOY:267;ToDOY:296;Ruler:'Venu<6E>e';Traits:'Idealismus, romantika a lehkomyslnost'),
(Sign:'Scorpio - <20>t<EFBFBD>r';FromDOY:297;ToDOY:326;Ruler:'Pluto a Mars';Traits:'V<><56>nivost, c<>lev<65>domost a <20><>rlivost'),
(Sign:'Sagittarius - St<53>elec';FromDOY:327;ToDOY:356;Ruler:'Jupiter';Traits:'Optimismus, aktivita a neklid'),
(Sign:'Capricorn - Kozoroh';FromDOY:357;ToDOY:366;Ruler:'Saturn';Traits:'Opatrnost, cti<74><69>dost a pesimismus'),
(Sign:'Capricorn - Kozoroh';FromDOY:1;ToDOY:20;Ruler:'Saturn';Traits:'Opatrnost, cti<74><69>dost a pesimismus'),
(Sign:'Aquarius - Vodn<64><6E>';FromDOY:21;ToDOY:50;Ruler:'Uran a Saturn';Traits:'Nez<65>vislost, sv<73>r<EFBFBD>znost a tvrdohlavost'),
(Sign:'Pisces - Ryby';FromDOY:51;ToDOY:80;Ruler:'Neptun a Jupiter';Traits:'Starostlivost, intuitivnost a neur<75>itost')
);
{$ENDIF}
ZodiacEn :array[0..12] of record
Sign :string;
FromDOY, ToDOY :integer;
Ruler,Traits :string;
end = (
(Sign:'Aries';FromDOY:81;ToDOY:111;Ruler:'Mars';Traits:'Bravery, energy and impatience '),
(Sign:'Taurus';FromDOY:112;ToDOY:142;Ruler:'Venus';Traits:'Resoluteness, warmth of feeling and stubborness'),
(Sign:'Gemini';FromDOY:143;ToDOY:173;Ruler:'Mercury';Traits:'Agility, versatility and inconstancy'),
(Sign:'Cancer';FromDOY:174;ToDOY:204;Ruler:'Moon';Traits:'Inventibility, sensitivity and self-possession'),
(Sign:'Leo';FromDOY:205;ToDOY:235;Ruler:'Sun';Traits:'Strength, creativity and self-confidence'),
(Sign:'Virgo';FromDOY:236;ToDOY:266;Ruler:'Mercury';Traits:'Modesty, practicality and loftiness'),
(Sign:'Libra';FromDOY:267;ToDOY:296;Ruler:'Venus';Traits:'Idealist, romantic and improvidence'),
(Sign:'Scorpio';FromDOY:297;ToDOY:326;Ruler:'Pluto and Mars';Traits:'Passion, resolution and jealousy'),
(Sign:'Sagittarius';FromDOY:327;ToDOY:356;Ruler:'Jupiter';Traits:'Optimistic, active and unquiet'),
(Sign:'Capricorn';FromDOY:357;ToDOY:366;Ruler:'Saturn';Traits:'Prudent, ambitiousness and pesimistic'),
(Sign:'Capricorn';FromDOY:1;ToDOY:20;Ruler:'Saturn';Traits:'Prudent, ambitiousness and pesimistic'),
(Sign:'Aquarius';FromDOY:21;ToDOY:50;Ruler:'Uran and Saturn';Traits:'Independent, individual and stubborn'),
(Sign:'Pisces';FromDOY:51;ToDOY:80;Ruler:'Neptun and Jupiter';Traits:'Careful, intuitive and casual')
);
type
TTzSpecificLocalTimeToSystemTime = function (lpTimeZoneInformation: PTimeZoneInformation; var pLocalTime, pUniversalTime: TSystemTime): BOOL; stdcall;
TSystemTimeToTzSpecificLocalTime = function (lpTimeZoneInformation: PTimeZoneInformation; var pUniversalTime, pLocalTime: TSystemTime): BOOL; stdcall;
var
TzSpecificLocalTimeToSystemTime: TTzSpecificLocalTimeToSystemTime = nil;
SystemTimeToTzSpecificLocalTime: TSystemTimeToTzSpecificLocalTime = nil;
implementation
uses {$IFDEF RAD9PLUS}
System.Types, System.DateUtils, System.Timespan, System.Win.Registry
{$ELSE}
Types, DateUtils, Registry
{$ENDIF}
;
procedure ResetMemory(out P; Size: Longint);
begin
if Size>0 then begin
Byte(P):=0;
FillChar(P,Size,0);
end;
end;
function UTCToSystemTime(UTC : TDateTime) : TDateTime;
var
TimeZoneInf: _TIME_ZONE_INFORMATION;
UTCTime,LocalTime: TSystemTime;
begin
if GetTimeZoneInformation(TimeZoneInf)<$FFFFFFFF then begin
DatetimetoSystemTime(UTC,UTCTime);
if SystemTimeToTzSpecificLocalTime(@TimeZoneInf,UTCTime,LocalTime) then begin
result:=SystemTimeToDateTime(LocalTime);
end else
result:=UTC;
end else
result:=UTC;
end;
function GetDateTimeForBiasSystemTime(ADateTime: TSystemTime; AGivenYear: Integer): TDateTime;
var
Year, Month, Day: Word;
Hour, Minute, Second, MilliSecond: Word;
begin
with ADateTime do begin
wYear:=AGivenYear;
while not TryEncodeDayOfWeekInMonth(wYear,wMonth,wDay,wDayOfWeek,Result) do
Dec(wDay);
DecodeDateTime(Result,Year,Month,Day,Hour,Minute,Second,MilliSecond);
Result:=EncodeDateTime(Year,Month,Day,wHour,wMinute,wSecond,wMilliseconds);
end;
end;
function GetBiasForDate(ADateTime: TDateTime): Integer;
var
tzi: TIME_ZONE_INFORMATION;
st,dt: TDateTime;
s: string;
begin
s:=GetCurrentTimezoneKeyName;
GetTimeZone(s,tzi,YearOf(ADatetime));
st:=GetDateTimeForBiasSystemTime(tzi.StandardDate,YearOf(ADateTime));
dt:=GetDateTimeForBiasSystemTime(tzi.DaylightDate,YearOf(ADateTime));
if tzi.StandardDate.wMonth=0 then
Result:=tzi.Bias
else if tzi.StandardDate.wMonth>tzi.DaylightDate.wMonth then
if (ADateTime<st) and (ADateTime >= dt) then
Result:=tzi.Bias+tzi.DaylightBias
else
Result:=tzi.Bias+tzi.StandardBias
else if (ADateTime >= st) and (ADateTime<dt) then
Result:=tzi.Bias+tzi.StandardBias
else
Result:=tzi.Bias+tzi.DaylightBias;
end;
function UTCToLocalDateTime(UTC: TDateTime): TDateTime;
var
sUTC,sLocal: TSystemTime;
begin
DateTimeToSystemTime(UTC,sUTC);
if SystemTimeToTzSpecificLocalTime(nil,sUTC,sLocal) then
Result:=SystemTimeToDateTime(sLocal)
else
Result:=IncMinute(UTC,-GetBiasForDate(UTC));
end;
function LocalDateTimeToUTC(Local: TDateTime): TDateTime;
var
sUTC,sLocal: TSystemTime;
begin
Result:=0;
if Assigned(TzSpecificLocalTimeToSystemTime) then begin
DateTimeToSystemTime(Local,sLocal);
if TzSpecificLocalTimeToSystemTime(nil,sLocal,sUTC) then
Result:=SystemTimeToDateTime(sUTC);
end;
if Result=0 then
Result:=IncMinute(Local,GetBiasForDate(Local));
end;
function CompareSysTime(st1, st2: TSystemTime): integer;
begin
if st1.wYear<st2.wYear then
Result:=-1
else
if st1.wYear>st2.wYear then
Result:=1
else
if st1.wMonth<st2.wMonth then
Result:=-1
else
if st1.wMonth>st2.wMonth then
Result:=1
else
if st1.wDayOfWeek<st2.wDayOfWeek then
Result:=-1
else
if st1.wDayOfWeek>st2.wDayOfWeek then
Result:=1
else
if st1.wDay<st2.wDay then
Result:=-1
else
if st1.wDay>st2.wDay then
Result:=1
else
if st1.wHour<st2.wHour then
Result:=-1
else
if st1.wHour>st2.wHour then
Result:=1
else
if st1.wMinute<st2.wMinute then
Result:=-1
else
if st1.wMinute>st2.wMinute then
Result:=1
else
if st1.wSecond<st2.wSecond then
Result:=-1
else
if st1.wSecond>st2.wSecond then
Result:=1
else
if st1.wMilliseconds<st2.wMilliseconds then
Result:=-1
else
if st1.wMilliseconds>st2.wMilliseconds then
Result:=1
else
Result:=0;
end;
function GetDaylightBias: Integer;
var
TimeZoneInfo: TTimeZoneInformation;
begin
FillChar(TimeZoneInfo, SizeOf(TimeZoneInfo), #0);
GetTimeZoneInformation(TimeZoneInfo);
Result:=TimeZoneInfo.DaylightBias;
end;
function GetDaylightName: string;
var
TimeZoneInfo: TTimeZoneInformation;
begin
FillChar(TimeZoneInfo, SizeOf(TimeZoneInfo), #0);
GetTimeZoneInformation(TimeZoneInfo);
Result:=TimeZoneInfo.DaylightName;
end;
function GetCurrentTimezoneKeyName: string;
const
rkTZKN = {HKEY_LOCAL_MACHINE\}'SYSTEM\CurrentControlSet\Control\TimeZoneInformation';
rvTZKN = 'TimeZoneKeyName';
begin
Result:='';
with TRegistry.Create do begin
Rootkey:=HKEY_LOCAL_MACHINE;
if OpenKeyReadOnly(rkTZKN) then begin
if ValueExists(rvTZKN) then
Result:=ReadString(rvTZKN);
CloseKey;
end;
end;
end;
procedure GetTimeZoneList(AList: TStringList);
var
i: Integer;
begin
AList.Clear;
with TRegistry.Create do
try
Rootkey:=HKEY_LOCAL_MACHINE;
if not OpenKeyReadOnly('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\') then
Exit;
GetKeyNames(AList);
CloseKey;
for i:=0 to AList.Count-1 do
if OpenKeyReadOnly(Format('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\%s',[AList[i]])) then begin
AList[i]:=AList[i]+'='+ReadString('Display');
CloseKey;
end;
finally
Free;
end;
end;
function GetTimeZone(AKeyName: string; out AData: TTimeZoneInformation; AYear: Word = 0): string;
var
s: string;
rtz: TRegistryTimeZoneInfo;
begin
Result:='';
ResetMemory(AData,SizeOf(AData));
if AYear=0 then
AYear:=YearOf(Date);
with TRegistry.Create do
try
Rootkey:=HKEY_LOCAL_MACHINE;
if not OpenKeyReadOnly(Format('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\%s',[AKeyName])) then
Exit;
Result:=ReadString('Display');
s:=ReadString('Std');
StringToWideChar(s,@(AData.StandardName),Length(s)+1);
s:=ReadString('Dlt');
StringToWideChar(s,@(AData.DaylightName),Length(s)+1);
ReadBinaryData('TZI',rtz,SizeOf(rtz));
AData.Bias:=rtz.Bias;
AData.StandardDate:=rtz.StandardDate;
AData.StandardBias:=rtz.StandardBias;
AData.DaylightDate:=rtz.DaylightDate;
AData.DaylightBias:=rtz.DaylightBias;
CloseKey;
if not OpenKeyReadOnly(Format('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\%s\Dynamic DST',[AKeyName])) then
Exit;
if not ValueExists(IntToStr(AYear)) then
Exit;
ReadBinaryData(IntToStr(AYear),rtz,SizeOf(rtz));
AData.Bias:=rtz.Bias;
AData.StandardDate:=rtz.StandardDate;
AData.StandardBias:=rtz.StandardBias;
AData.DaylightDate:=rtz.DaylightDate;
AData.DaylightBias:=rtz.DaylightBias;
CloseKey;
finally
Free;
end;
end;
function LocalDateTimeToTZ(AValue: TDateTime; ATZ: TTimeZoneInformation): TDateTime;
var
sLocal,sUTC: TSystemTime;
begin
Result:=0;
AValue:=LocalDatetimeToUTC(AValue);
if Assigned(SystemTimeToTzSpecificLocalTime) then begin
DateTimeToSystemTime(AValue,sUTC);
if SystemTimeToTzSpecificLocalTime(@ATZ,sUTC,sLocal) then
Result:=SystemTimeToDateTime(sLocal);
end;
end;
function IncWorkDays(ADT: TDateTime; ADays: Cardinal): TDateTime;
var
i: Cardinal;
begin
Result:=ADT;
i:=0;
while i<ADays do begin
Result:=Result+1;
if DayOfWeek(Result) in [2..6] then
Inc(i);
end;
end;
function DecWorkDays(ADT: TDateTime; ADays: Cardinal): TDateTime;
var
i: Cardinal;
begin
Result:=ADT;
i:=0;
while i<ADays do begin
Result:=Result-1;
if DayOfWeek(Result) in [2..6] then
Inc(i);
end;
end;
function FileTimeToDateTimeStr(FileTime: TFileTime): string;
begin
Result:=DateTimeToStr(FileTimeToDateTime(FileTime));
end;
function FileTimeToDateTime(FT: FILETIME; ConvertTimeToLocal: Boolean = False): TDateTime;
var
SysFTime: TSystemTime;
begin
try
FileTimeToSystemTime(FT,SysFTime);
Result:=SystemTimeTodateTime(SysFTime);
if ConvertTimeToLocal then
Result:=UTCToSystemTime(Result);
except
Result:=0;
end;
end;
function ParseDate(YYYYMMDD: string): TDatetime;
var
y,m,d: Word;
begin
y:=StrToInt(Copy(YYYYMMDD,1,4));
m:=StrToInt(Copy(YYYYMMDD,5,2));
d:=StrToInt(Copy(YYYYMMDD,7,2));
Result:=EncodeDate(y,m,d);
end;
function UTCToDateTime(UTC: Cardinal; ConvertTimeToLocal: Boolean = False): TDateTime;
var
d: LARGE_INTEGER;
ft: FILETIME;
begin
d.QuadPart:=365*24*60*60;
d.QuadPart:=((1970-1601)*d.QuadPart+UTC+89*24*60*60+3600)*10000000;
ft.dwLowDateTime:=d.LowPart;
ft.dwHighDateTime:=d.HighPart;
Result:=FiletimeToDateTime(ft,ConvertTimeToLocal);
end;
function UTCToDateTimeEx(UTC: int64; CorrectToLocal: Boolean = True): TDateTime;
var
d: LARGE_INTEGER;
ft: FILETIME;
begin
d.QuadPart:=365*24*60*60;
d.QuadPart:=((1970-1601)*d.QuadPart+89*24*60*60)*10000000+UTC*10;
ft.dwLowDateTime:=d.LowPart;
ft.dwHighDateTime:=d.HighPart;
try
Result:=FiletimeToDateTime(ft,CorrectToLocal);
if YearOf(Result)>YearOf(Now) then
Result:=IncYear(Result,-1970+1601);
except
Result:=0;
end;
end;
function Int64ToDateTime(UTC: Int64; ConvertTimeToLocal: Boolean = False): TDateTime;
var
d: LARGE_INTEGER;
ft: FILETIME;
begin
d.QuadPart:=UTC;
ft.dwLowDateTime:=d.LowPart;
ft.dwHighDateTime:=d.HighPart;
Result:=FiletimeToDateTime(ft);
if ConvertTimeToLocal then
Result:=UTCToLocalDateTime(Result);
end;
function DSTDate2Date(dstDate: TSystemTime; year: word): TDateTime;
begin
Result:=0;
if dstDate.wMonth=0 then
Exit;
repeat
if dstDate.wYear=0 then
try
Result:=EncodeDayOfWeekInMonth(year,dstDate.wMonth,dstDate.wDay,dstDate.wDayOfWeek)+
EncodeTime(dstDate.wHour,dstDate.wMinute,dstDate.wSecond,dstDate.wMilliseconds);
except
Dec(dstDate.wDay);
end
else
Result:=SystemTimeToDateTime(dstDate);
until Result>0;
end;
function EasterSunday(const Year: Word): TDateTime;
var
C, I, J, H, G, L: Integer;
D, M: Word;
begin
G:=Year mod 19;
C:=Year div 100;
H:=(C-C div 4-(8*C+13) div 25+19*G+15) mod 30;
I:=H-(H div 28)*(1-(H div 28)*(29 div (H+1))*((21-G) div 11));
J:=(Year+Year div 4+I+2-C+C div 4) mod 7;
L:=I-J;
M:=3+(L+40) div 44;
D:=L+28-31*(M div 4);
Result:=EncodeDate(Year,M,D);
end;
function GetWorkDays(ADT: TDatetime; ACount: Integer): Integer;
var
sd: TDateTime;
begin
Result:=0;
sd:=ADT;
repeat
if DayOfWeek(ADT) in [2..6] then
Inc(Result);
if ACount<0 then
ADT:=ADT-1
else
ADT:=ADT+1;
until Result=abs(ACount);
Result:=Round(abs(int(ADT)-int(sd)));
end;
function DateToStrDef(ADT: TDateTime; ADef: string = ''): string;
begin
if ADT<=0 then
Result:=ADef
else
Result:=DateToStr(ADT);
end;
function DateTimeToStrDef(ADT: TDateTime; ADef: string = ''; AValidDateLimit: TDatetime = 0): string;
begin
if ADT<=AValidDateLimit then
Result:=ADef
else
Result:=DateTimeToStr(ADT);
end;
function DateTimeToFileTime(dt: TDateTime): FILETIME;
var
st: SYSTEMTIME;
begin
DateTimeToSystemTime(dt,st);
SystemTimeToFileTime(st,Result);
end;
function RFC822DateToDateTime(RFC822DateTime: string; ADefault: TDatetime = 0): TDateTime;
const
RFC822ConvertDateTimeConvertError = '"%s" is not valid RFC822 datetime';
DayArray: array[0..6] of string = ('Mon','Tue','Wed','Thu','Fri','Sat','Sun');
MonthArray: array[0..11] of string = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
ZoneArray: array[0..14] of string = ('UT','GMT','EST','EDT','CST','CDT','MST','MDT','PST','PDT','Z','A','M','N','Y');
var
lString: string;
lDayName: string;
lMonthName: string;
I: Integer;
lProceed: Boolean;
lDay: Integer;
lMonth: Integer;
lYear: Integer;
lTmp: Integer;
lHours: Integer;
lMinutes: Integer;
lSeconds: Integer;
lTimeZone: TTimeZoneInformation;
lLocalStringTime: TDateTime;
lTimeZoneName: string;
lTimeZoneIndex: Integer;
lLocalDiffHours: Integer;
lLocalDiffMinutes: Integer;
lAddLocalDiff: Boolean;
begin
RFC822DateTime:=StringReplace(RFC822DateTime,'GTM','GMT',[rfIgnorecase]);
lTimeZoneIndex:=-1;
lAddLocalDiff:=False;
lMonth:=-1;
lTmp:=0;
lString:=RFC822DateTime;
lProceed:=False;
if Pos(',',lString)>0 then
begin
lDayName:=Copy(lString,1,3);
for i:=0 to Length(DayArray)-1 do begin
if lDayName=DayArray[i] then begin
lProceed:=True;
Break;
end;
end;
Delete(lString,1,5);
end;
if lProceed then begin
if not TryStrToInt(Copy(lString,1,2), lDay) then
lProceed:=False;
end;
if lProceed then begin
lMonthName:=Copy(lString,4,3);
lProceed:=False;
for i:=0 to Length(MonthArray)-1 do begin
if lMonthName=MonthArray[I] then begin
lProceed:=True;
lMonth:=Succ(I);
Break;
end;
end;
end;
if lProceed then begin
if not TryStrToInt(Copy(lString,8,4), lYear) then begin
// might be only 2 characters long
if not TryStrToInt(Copy(lString,8,2), lYear) then
lProceed:=False
else
lTmp:=2;
end else
lTmp:=4;
end;
if lProceed then begin
lTmp:=8+Succ(lTmp);
if not TryStrToInt(Copy(lString,lTmp,2),lHours) then
lProceed:=False;
end;
if lProceed then begin
Inc(lTmp,3);
if not TryStrToInt(Copy(lString, lTmp, 2), lMinutes) then
lProceed:=False;
end;
if lProceed then begin
Inc(lTmp,3);
if not TryStrToInt(Copy(lString,lTmp,2),lSeconds) then
// Just proceed, seconds are optional.
lSeconds:=0;
end;
if lProceed then begin
Inc(lTmp,3); // Start of TimeZone
lTimeZoneName:=Copy(lString,lTmp,3); // e.g. "GMT"
if (Copy(lTimeZoneName,1,1)='-') or
(Copy(lTimeZoneName,1,1)='+') or
(Length(lTimeZoneName) = 0) then
// Assume UTC
lTimeZoneIndex:=0
else begin
lProceed:=False;
if Length(lTimeZoneName)=3 then begin
for i:=0 to Length(ZoneArray)-1 do begin
if ZoneArray[i]=lTimeZoneName then begin
lTimeZoneIndex:=i;
lProceed:=True;
Break;
end;
end;
end;
if not lProceed then begin
// Try the ones with only 2 letters
for i:=0 to Length(ZoneArray)-1 do begin
if ZoneArray[i]=Copy(lTimeZoneName,1,2) then begin
lTimeZoneIndex:=i;
lProceed:=True;
Break;
end;
end;
end;
if not lProceed then begin
// Try the ones with only 1 letter
for i:=0 to Length(ZoneArray)-1 do begin
if ZoneArray[i]=lTimeZoneName[1] then begin
lTimeZoneIndex:=i;
lProceed:=True;
Break;
end;
end;
end;
Inc(lTmp,Length(ZoneArray[lTimeZoneIndex])); // Begin of+/ -
end;
end;
if lProceed then begin
// Get local differential hours
lAddLocalDiff:=Copy(lString,lTmp,1)='+';
Inc(lTmp,1); // Begin of local diff hours
if lTmp<Length(lString) then begin
// Has local differential hours
if not TryStrToInt(Copy(lString,lTmp,2),lLocalDiffHours) then
lProceed:=False
end else begin
// No local diff time
lLocalDiffHours:=-1;
lLocalDiffMinutes:=-1;
end;
end;
if (lProceed) and (lLocalDiffHours<>-1) then begin
// Get local differential minutes
Inc(lTmp,2); // Begin of local diff minutes
if not TryStrToInt(Copy(lString,lTmp,2),lLocalDiffMinutes) then
lProceed:=False
end;
if lProceed then begin
// Create current local time of string as TDateTime
lLocalStringTime:=EncodeDate(lYear,lMonth,lDay)+EncodeTime(lHours,lMinutes,lSeconds,0);
case lTimeZoneIndex of
0,1,10: lTmp:=0; // UT, GMT, Z
2: lTmp:=5; // EST,-5
3: lTmp:=4; // EDT,-4
4: lTmp:=6; // CST,-6
5: lTmp:=5; // CDT,-5
6: lTmp:=7; // MST,-7
7: lTmp:=6; // MDT,-6
8: lTmp:=8; // PST,-8
9: lTmp:=7; // PDT,-7
11: lTmp:=1; // A,-1
12: lTmp:=12; // M,-12
13: lTmp:=-1; // N,+1
14: lTmp:=-12; // Y,+12
end;
// Calculate the UTC-Time of the given string
lLocalStringTime:=lLocalStringTime+(lTmp*OneHour);
if lLocalDiffHours<>-1 then begin
if lAddLocalDiff then
lLocalStringTime:=lLocalStringTime-(lLocalDiffHours*OneHour)-(lLocalDiffMinutes*OneMinute)
else
lLocalStringTime:=lLocalStringTime+(lLocalDiffHours*OneHour)+(lLocalDiffMinutes*OneMinute);
end;
// Now calculate the time in local format
if GetTimeZoneInformation(lTimeZone)=TIME_ZONE_ID_DAYLIGHT then begin
Result:=lLocalStringTime-((lTimeZone.Bias+lTimeZone.DaylightBias)*OneMinute);
end else begin
Result:=lLocalStringTime-((lTimeZone.Bias+lTimeZone.StandardBias)*OneMinute);
end;
end else begin
//raise EConvertError.Create(Format(RFC822ConvertDateTimeConvertError,[RFC822DateTime]));
Result:=ADefault;
end;
end;
function GreaterOrEquals(ANow,AThen: TDateTime): Boolean;
begin
Result:=(CompareDateTime(ANow,AThen)<>LessThanValue);
end;
function LessOrEquals(ANow,AThen: TDateTime): Boolean;
begin
Result:=(CompareDateTime(ANow,AThen)<>GreaterThanValue);
end;
function Less(ANow,AThen: TDateTime): Boolean;
begin
Result:=(CompareDateTime(ANow,AThen)=LessThanValue);
end;
function Greater(ANow,AThen: TDateTime): Boolean;
begin
Result:=(CompareDateTime(ANow,AThen)=GreaterThanValue);
end;
function IsTimeInRange(ATime: TDateTime; AStartTime, AEndTime: TDateTime; AInclusive: Boolean = True): Boolean;
var
LTime, LStartTime, LEndTime: TDateTime;
begin
LTime:=TimeOf(ATime);
LStartTime:=TimeOf(AStartTime);
LEndTime:=TimeOF(AEndTime);
if CompareTime(LEndTime,LStartTime)=LessThanValue then
if AInclusive then
Result:=(CompareTime(LStartTime,LTime)<>GreaterThanValue) or (CompareTime(LTime,LEndTime)<>GreaterThanValue)
else
Result:=(CompareTime(LStartTime,LTime)=LessThanValue) or (CompareTime(LTime,LEndTime)=LessThanValue)
else
if AInclusive then
Result:=(CompareTime(LStartTime,LTime)<>GreaterThanValue) and (CompareTime(LTime,LEndTime)<>GreaterThanValue)
else
Result:=(CompareTime(LStartTime,LTime)=LessThanValue) and (CompareTime(LTime,LEndTime)=LessThanValue);
end;
function IsDateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
begin
if aInclusive then
Result:=(CompareDateTime(AStartDateTime,ADateTime)<>GreaterThanValue) and (CompareDateTime(ADateTime,AEndDateTime)<>GreaterThanValue)
else
Result:=(CompareDateTime(AStartDateTime,ADateTime)=LessThanValue) and (CompareDateTime(ADateTime,AEndDateTime)=LessThanValue);
end;
function IsDateInRange(ADate: TDateTime; AStartDate, AEndDate: TDateTime; AInclusive: Boolean = True): Boolean;
begin
if AInclusive then
Result:=(CompareDate(DateOf(AStartDate),DateOf(ADate))<>GreaterThanValue) and (CompareDate(DateOf(ADate),DateOf(AEndDate))<>GreaterThanValue)
else
Result:=(CompareDate(DateOf(AStartDate),DateOf(ADate))=LessThanValue) and (CompareDate(DateOf(ADate),DateOf(AEndDate))=LessThanValue);
end;
function SecondsBetweenSgn(ANow,AThen: TDateTime): Integer;
begin
Result:=CompareDatetime(AThen,ANow)*SecondsBetween(ANow,AThen);
end;
function MinutesBetweenSgn(ANow,AThen: TDateTime): Integer;
begin
Result:=CompareDatetime(AThen,ANow)*MinutesBetween(ANow,AThen);
end;
function HoursBetweenSgn(ANow,AThen: TDateTime): Integer;
begin
Result:=CompareDatetime(AThen,ANow)*HoursBetween(ANow,AThen);
end;
function DaysBetweenSgn(ANow,AThen: TDateTime): Integer;
begin
Result:=CompareDatetime(AThen,ANow)*DaysBetween(ANow,AThen);
end;
function WeeksBetweenSgn(ANow,AThen: TDateTime): Integer;
begin
Result:=CompareDatetime(AThen,ANow)*WeeksBetween(ANow,AThen);
end;
function SecondsToTime(const ASeconds: Int64): TDatetime;
const
SecPerDay = 86400;
SecPerHour = 3600;
SecPerMinute = 60;
var
ms, ss, mm, hh, dd: Cardinal;
begin
dd:=ASeconds div SecPerDay;
hh:=(ASeconds mod SecPerDay) div SecPerHour;
mm:=((ASeconds mod SecPerDay) mod SecPerHour) div SecPerMinute;
ss:=((ASeconds mod SecPerDay) mod SecPerHour) mod SecPerMinute;
ms:=0;
Result:=dd+EncodeTime(hh,mm,ss,ms);
end;
function FormatTicks(AValue :Int64; AWholeSecondsOnly: Boolean = True) :string;
{$IFDEF RAD9PLUSxxx}
var
ts: TTimeSpan;
begin
ts:=TTimeSpan.Create(AValue);
Result:=Format('%2.2d:%2.2d:%2.2d',[ts.Hours,ts.Minutes,ts.Seconds]);
if not AWholeSecondsOnly then
Result:=Result+Format('.%3.3d',[ts.Milliseconds]);
if ts.Days>0 then
Result:=Format('%3.3d %s',[ts.Days,Result]);
{$ELSE}
const
TicksPerMillisecond = 10000;
TicksPerSecond = 1000 * Int64(TicksPerMillisecond);
var
dt: TDateTime;
ms,d: Integer;
begin
dt:=SecondsToTime(Round(AValue/TicksPerSecond));
d:=DaysBetween(0,dt);
ms:=Integer((AValue div TicksPerMillisecond) mod 1000);
Result:=FormatDateTime('hh:mm:ss',dt);
if d>0 then
Result:=Format('%3.3d %s',[d,Result]);
if not AWholeSecondsOnly then
Result:=Result+Format('.%3.3d',[ms]);
{$ENDIF}
end;
function FormatSeconds(AValue :Int64; AShort: Boolean = True) :string;
{$IFDEF RAD9PLUSxxx}
var
ts: TTimeSpan;
begin
ts:=TTimeSpan.Create(0,0,0,AValue);
if AShort and (ts.Days=0) then
Result:=Format('%2.2d:%2.2d:%2.2d',[ts.Hours,ts.Minutes,ts.Seconds])
else
Result:=Format('%3.3d %2.2d:%2.2d:%2.2d',[ts.Days,ts.Hours,ts.Minutes,ts.Seconds]);
{$ELSE}
var
dt: TDateTime;
d: integer;
begin
dt:=SecondsToTime(AValue);
d:=DaysBetween(0,dt);
if AShort and (d=0) then
Result:=FormatDateTime('hh:mm:ss',dt)
else
Result:=Format('%3.3d %s',[d,FormatDateTime('hh:mm:ss',dt)]);
{$ENDIF}
end;
function FormatMilliseconds(AValue :Int64; AWholeSecondsOnly: Boolean = True; AShort: Boolean = True) :string;
{$IFDEF RAD9PLUSxxx}
var
ts: TTimeSpan;
begin
ts:=TTimeSpan.Create(0,0,0,0,AValue);
if AShort and (ts.Days=0) then
Result:=Format('%2.2d:%2.2d:%2.2d',[ts.Hours,ts.Minutes,ts.Seconds])
else
Result:=Format('%3.3d %2.2d:%2.2d:%2.2d',[ts.Days,ts.Hours,ts.Minutes,ts.Seconds]);
if not AWholeSecondsOnly then
Result:=Result+Format('.%3.3d',[ts.Milliseconds]);
{$ELSE}
var
dt: TDateTime;
ms,d: integer;
begin
dt:=SecondsToTime(Round(AValue/1000));
d:=DaysBetween(0,dt);
ms:=AValue mod 1000;
if AShort and (d=0) then
Result:=FormatDateTime('hh:mm:ss',dt)
else
Result:=Format('%3.3d %s',[d,FormatDateTime('hh:mm:ss',dt)]);
if not AWholeSecondsOnly then
Result:=Result+Format('.%3.3d',[ms]);
{$ENDIF}
end;
function XMLStrToDateTime(const AString: string): TDateTime;
begin
Result:=XMLStrToDateTimeDef(AString, 0);
end;
function XMLStrToDateTimeDef(const AString: string; const ADefDateTime: TDateTime = 0): TDateTime;
begin
if not XMLTryStrToDateTime(aString, Result) then
Result:=aDefDateTime;
end;
function XMLTryStrToDateTime(const AString: string; var ADatetime: TDateTime): Boolean;
var
xYear, xMonth, xDay, xHour, xMinute, xSecond, xMS: Integer;
sYear, sMonth, sDay, sHour, sMinute, sSecond, sMS: string;
begin
sYear:=Copy(AString,1,4);
sMonth:=Copy(AString,6,2);
sDay:=Copy(AString,9,2);
sHour:=Copy(AString,12,2);
sMinute:=Copy(AString,15,2);
sSecond:=Copy(AString,18,2);
sMS:=Copy(AString,21,3);
Result:=TryStrToInt(sYear,xYear) and
TryStrToInt(sMonth,xMonth) and
TryStrToInt(sDay,xDay);
if Result then begin
xHour:=StrToIntDef(sHour,0);
xMinute:=StrToIntDef(sMinute,0);
xSecond:=StrToIntDef(sSecond,0);
xMS:=StrToIntDef(sMS,0);
Result:=TryEncodeDateTime(xYear,xMonth,xDay,xHour,xMinute,xSecond,xMS,ADatetime);
end;
if not Result then
ADatetime:=0;
end;
initialization
TzSpecificLocalTimeToSystemTime:=TTzSpecificLocalTimeToSystemTime(GetProcAddress(GetModuleHandle('Kernel32.dll'),'TzSpecificLocalTimeToSystemTime'));
SystemTimeToTzSpecificLocalTime:=TSystemTimeToTzSpecificLocalTime(GetProcAddress(GetModuleHandle('Kernel32.dll'),'SystemTimeToTzSpecificLocalTime'));
end.