1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/afrusrsc-superobject

В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
supertimezone.pas 36 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
jxq Отправлено 18.03.2020 09:24 be0932b
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376
unit supertimezone;
interface
uses
Windows, Registry, SysUtils, Math, Generics.Collections,
supertypes;
type
TSuperTimeZone = class
private
const
TZ_TZI_KEY = '\SYSTEM\CurrentControlSet\Control\TimeZoneInformation'; { Vista and + }
TZ_KEY = '\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\';
TZ_KEYNAME = 'TimeZoneKeyName';
private
FName: SOString;
function GetName: SOString;
{ Windows Internals }
function TzSpecificLocalTimeToSystemTime(
const lpTimeZoneInformation: PTimeZoneInformation;
var lpLocalTime, lpUniversalTime: TSystemTime): BOOL;
function SystemTimeToTzSpecificLocalTime(
const lpTimeZoneInformation: PTimeZoneInformation;
var lpUniversalTime, lpLocalTime: TSystemTime): BOOL;
function GetTimezoneBias(const pTZinfo: PTimeZoneInformation;
lpFileTime: PFileTime; islocal: Boolean; pBias: PLongint): Boolean;
function CompTimeZoneID(const pTZinfo: PTimeZoneInformation;
lpFileTime: PFileTime; IsLocal: Boolean): LongWord;
function DayLightCompareDate(const date: PSystemTime;
const compareDate: PSystemTime): Integer;
private
class constructor Init;
class destructor Finish;
class var FCacheCS: TRTLCriticalSection;
class var FCache: TObjectDictionary<string, TSuperTimeZone>;
class function GetSuperTimeZoneInstance(const Name: string): TSuperTimeZone; static;
class function GetLocalSuperTimeZoneInstance: TSuperTimeZone; static;
public
constructor Create(const TimeZoneName: SOString = '');
{ ISO8601 formatted date Parser }
class function ParseISO8601Date(const ISO8601Date: SOString;
var st: TSystemTime; var dayofyear: Integer; var week: Word; var bias: Integer;
var havetz, havedate: Boolean): Boolean;
{ Conversions }
function LocalToUTC(const DelphiDateTime: TDateTime): TDateTime;
function UTCToLocal(const DelphiDateTime: TDateTime): TDateTime;
function JavaToDelphi(const JavaDateTime: Int64): TDateTime;
function DelphiToJava(const DelphiDateTime: TDateTime): Int64;
function JavaToISO8601(JavaDateTime: Int64): SOString;
function DelphiToISO8601(DelphiDateTime: TDateTime): SOString;
function ISO8601ToJava(const ISO8601Date: SOString; var JavaDateTime: Int64): Boolean;
function ISO8601ToDelphi(const ISO8601Date: SOString; var DelphiDateTime: TDateTime): Boolean;
{ TZ Info }
class function GetCurrentTimeZone: SOString;
function GetTimeZoneInformation(Year: Word; var TZI: TTimeZoneInformation): Boolean;
function GetDaylightDisabled: Boolean;
property Name: SOString read GetName;
{ Builder }
class property Local: TSuperTimeZone read GetLocalSuperTimeZoneInstance;
class property Zone[const TimeZoneName: string]: TSuperTimeZone read GetSuperTimeZoneInstance;
end;
{$IFDEF MSWINDOWS}
{$WARN SYMBOL_PLATFORM OFF}
(* NOT DST Aware *)
{ Windows 2000+ }
function _SystemTimeToTzSpecificLocalTime(
lpTimeZoneInformation: PTimeZoneInformation;
var lpUniversalTime, lpLocalTime: TSystemTime): BOOL; stdcall; external kernel32 name 'SystemTimeToTzSpecificLocalTime' delayed;
{ Windows XP+ }
function _TzSpecificLocalTimeToSystemTime(
lpTimeZoneInformation: PTimeZoneInformation;
var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall; external kernel32 name 'TzSpecificLocalTimeToSystemTime' delayed;
(* EXtended version - DST Aware *)
{ Windows 7+ }
function _TzSpecificLocalTimeToSystemTimeEx(
const lpTimeZoneInformation: PDynamicTimeZoneInformation;
const lpLocalTime: PSystemTime; var lpUniversalTime: TSystemTime): BOOL; stdcall; external kernel32 name 'TzSpecificLocalTimeToSystemTimeEx' delayed;
{ Windows 7+ }
function _SystemTimeToTzSpecificLocalTimeEx(
const lpTimeZoneInformation: PDynamicTimeZoneInformation;
const lpUniversalTime: PSystemTime; var lpLocalTime: TSystemTime): BOOL; stdcall; external kernel32 name 'SystemTimeToTzSpecificLocalTimeEx' delayed;
{ Convert Local <=> UTC for specific time-zones using the Windows API only. NOT Guaranteed to work }
function _ConvertLocalDateTimeToUTC(const TimeZoneName: SOString;
const Local: TDateTime; var UTC: TDateTime): Boolean;
function _ConvertUTCDateTimeToLocal(const TimeZoneName: SOString;
const UTC: TDateTime; var Local: TDateTime): Boolean;
{$WARN SYMBOL_PLATFORM ON}
{$ENDIF}
implementation
{$IFDEF MSWINDOWS}
{ Convert Local -> UTC for specific time-zones using the Windows API only. NOT Guaranteed to work }
function _ConvertLocalDateTimeToUTC(const TimeZoneName: SOString;
const Local: TDateTime; var UTC: TDateTime): Boolean;
var
DTZI: TDynamicTimeZoneInformation;
local_st, utc_st: TSystemTime;
begin
if not CheckWin32Version(6, 1) then
begin
Result := False;
Exit;
end;
{ We work with system times }
DateTimeToSystemTime(Local, local_st);
{ Get current Dynamic TimeZone Information }
FillChar(DTZI, SizeOf(TDynamicTimeZoneInformation), 0);
GetDynamicTimeZoneInformation(DTZI);
{ Replaces the TimeZoneKeyName member with specified TimeZoneName }
Move(TimeZoneName[1], DTZI.TimeZoneKeyName, (Length(TimeZoneName) + 1) * SizeOf(SOChar));
{ Retrieves the TimeZoneInformation structure and convert the local time to utc }
if _TzSpecificLocalTimeToSystemTimeEx(@DTZI, @local_st, utc_st) then
begin
{ We really want Delphi TDateTime }
UTC := SystemTimeToDateTime(utc_st);
Result := True;
end
else
Result := False;
end;
{ Convert UTC -> Local for specific time-zones using the Windows API only. NOT Guaranteed to work }
function _ConvertUTCDateTimeToLocal(const TimeZoneName: SOString;
const UTC: TDateTime; var Local: TDateTime): Boolean;
var
DTZI: TDynamicTimeZoneInformation;
utc_st, local_st: TSystemTime;
begin
if not CheckWin32Version(6, 1) then
begin
Result := False;
Exit;
end;
{ We work with system times }
DateTimeToSystemTime(UTC, utc_st);
{ Get current Dynamic TimeZone Information }
FillChar(DTZI, SizeOf(TDynamicTimeZoneInformation), 0);
GetDynamicTimeZoneInformation(DTZI);
{ Replaces the TimeZoneKeyName member with specified TimeZoneName }
Move(TimeZoneName[1], DTZI.TimeZoneKeyName[0], Length(TimeZoneName) * SizeOf(SOChar));
{ Retrieves the TimeZoneInformation structure and convert the local time to utc }
if _SystemTimeToTzSpecificLocalTimeEx(@DTZI, @utc_st, local_st) then
begin
{ We really want Delphi TDateTime }
Local := SystemTimeToDateTime(local_st);
Result := True;
end
else
Result := False;
end;
{$ENDIF}
{ TSuperDate }
class constructor TSuperTimeZone.Init;
begin
InitializeCriticalSection(FCacheCS);
FCache := TObjectDictionary<string, TSuperTimeZone>.Create([doOwnsValues]);
end;
class destructor TSuperTimeZone.Finish;
begin
FCache.Free;
DeleteCriticalSection(FCacheCS);
end;
class function TSuperTimeZone.GetSuperTimeZoneInstance(
const Name: string): TSuperTimeZone;
begin
EnterCriticalSection(FCacheCS);
try
if not FCache.TryGetValue(Name, Result) then
begin
Result := TSuperTimeZone.Create(Name);
FCache.Add(Name, Result);
end;
finally
LeaveCriticalSection(FCacheCS);
end;
end;
class function TSuperTimeZone.GetLocalSuperTimeZoneInstance: TSuperTimeZone;
begin
Result := TSuperTimeZone.GetSuperTimeZoneInstance('');
end;
constructor TSuperTimeZone.Create(const TimeZoneName: SOString);
begin
inherited Create;
FName := TimeZoneName;
end;
function TSuperTimeZone.LocalToUTC(const DelphiDateTime: TDateTime): TDateTime;
var
local, utc: TSystemTime;
tzi: TTimeZoneInformation;
begin
DateTimeToSystemTime(DelphiDateTime, local);
if GetTimeZoneInformation(local.wYear, tzi) and TzSpecificLocalTimeToSystemTime(@tzi, local, utc) then
Result := SystemTimeToDateTime(utc)
else
Result := DelphiDateTime;
end;
function TSuperTimeZone.UTCToLocal(const DelphiDateTime: TDateTime): TDateTime;
var
utc, local: TSystemTime;
tzi: TTimeZoneInformation;
begin
DateTimeToSystemTime(DelphiDateTime, utc);
if GetTimeZoneInformation(utc.wYear, tzi) and SystemTimeToTzSpecificLocalTime(@tzi, utc, local) then
Result := SystemTimeToDateTime(local)
else
Result := DelphiDateTime;
end;
function TSuperTimeZone.DelphiToJava(const DelphiDateTime: TDateTime): Int64;
var
local, utc, st: TSystemTime;
tzi: TTimeZoneInformation;
begin
DateTimeToSystemTime(DelphiDateTime, local);
if GetTimeZoneInformation(local.wYear, tzi) and TzSpecificLocalTimeToSystemTime(@tzi, local, utc) then
st := utc
else
st := local;
Result := Round((SystemTimeToDateTime(st) - 25569) * 86400000);
end;
function TSuperTimeZone.JavaToDelphi(const JavaDateTime: Int64): TDateTime;
var
utc, local: TSystemTime;
tzi: TTimeZoneInformation;
begin
DateTimeToSystemTime(25569 + (JavaDateTime / 86400000), utc);
if GetTimeZoneInformation(utc.wYear, tzi) and SystemTimeToTzSpecificLocalTime(@tzi, utc, local) then
Result := SystemTimeToDateTime(local)
else
Result := SystemTimeToDateTime(utc);
end;
function TSuperTimeZone.DelphiToISO8601(
DelphiDateTime: TDateTime): SOString;
const
ISO_Fmt = '%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%d';
TZ_Fmt = '%s%.2d:%.2d';
var
local, utc: TSystemTime;
tzi: TTimeZoneInformation;
bias: TDateTime;
h, m, d: Word;
iso: SOString;
begin
DateTimeToSystemTime(DelphiDateTime, local);
iso := Format(ISO_Fmt, [
local.wYear, local.wMonth, local.wDay,
local.wHour, local.wMinute, local.wSecond, local.wMilliseconds]);
if GetTimeZoneInformation(local.wYear, tzi) and TzSpecificLocalTimeToSystemTime(@tzi, local, utc) then
begin
bias := SystemTimeToDateTime(local) - SystemTimeToDateTime(utc);
DecodeTime(bias, h, m, d, d);
case Sign(bias) of
-1: Result := iso + Format(TZ_Fmt, [ '-', h, m ]);
0: Result := iso + 'Z';
+1: Result := iso + Format(TZ_Fmt, [ '+', h, m ]);
end;
end
else
Result := iso;
end;
function TSuperTimeZone.JavaToISO8601(JavaDateTime: Int64): SOString;
begin
Result := DelphiToISO8601(JavaToDelphi(JavaDateTime));
end;
function TSuperTimeZone.ISO8601ToDelphi(const ISO8601Date: SOString;
var DelphiDateTime: TDateTime): Boolean;
var
JavaDateTime: Int64;
begin
Result := ISO8601ToJava(ISO8601Date, JavaDateTime);
if Result then
DelphiDateTime := JavaToDelphi(JavaDateTime);
end;
function TSuperTimeZone.ISO8601ToJava(const ISO8601Date: SOString;
var JavaDateTime: Int64): Boolean;
var
st: TSystemTime;
dayofyear: Integer;
week: Word;
bias: Integer;
havetz, havedate: Boolean;
tzi: TTimeZoneInformation;
utc: TSystemTime;
m: Word;
DayTable: PDayTable;
begin
if ParseISO8601Date(ISO8601Date, st, dayofyear, week, bias, havetz, havedate) then
begin
if (not havetz) and GetTimeZoneInformation(st.wYear, tzi) and TzSpecificLocalTimeToSystemTime(@tzi, st, utc) then
bias := Trunc((SystemTimeToDateTime(st) - SystemTimeToDateTime(utc)) * MinsPerDay);
JavaDateTime := st.wMilliseconds + st.wSecond * 1000 + (st.wMinute + bias) * 60000 + st.wHour * 3600000;
if havedate then
begin
DayTable := @MonthDays[IsLeapYear(st.wYear)];
if st.wMonth <> 0 then
begin
if not (st.wMonth in [1..12]) or (DayTable^[st.wMonth] < st.wDay) then
begin
Result := False;
Exit;
end;
for m := 1 to st.wMonth - 1 do
Inc(JavaDateTime, Int64(DayTable^[m]) * 86400000);
end;
Dec(st.wYear);
Inc(JavaDateTime, Int64(
(st.wYear * 365) + (st.wYear div 4) - (st.wYear div 100) +
(st.wYear div 400) + st.wDay + dayofyear - 719163) * 86400000);
end;
Result := True;
end
else
Result := False;
end;
function TSuperTimeZone.GetName: SOString;
begin
if FName <> '' then
Result := FName
else
Result := GetCurrentTimeZone;
end;
class function TSuperTimeZone.GetCurrentTimeZone: SOString;
begin
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
if OpenKeyReadOnly(TZ_TZI_KEY) and ValueExists(TZ_KEYNAME) then
{ Windows Vista+ }
Result := Trim(ReadString(TZ_KEYNAME))
else
begin
{ Windows 2000/XP }
CloseKey;
RootKey := HKEY_CURRENT_USER;
if OpenKeyReadOnly(TZ_KEY) and ValueExists(TZ_KEYNAME) then
Result := Trim(ReadString(TZ_KEYNAME))
else
begin
CloseKey;
RootKey := HKEY_USERS;
if OpenKeyReadOnly('.DEFAULT\' + TZ_KEY) and ValueExists(TZ_KEYNAME) then
Result := Trim(ReadString(TZ_KEYNAME))
else
Result := '';
end;
end;
finally
CloseKey;
Free;
end;
end;
function TSuperTimeZone.GetDaylightDisabled: Boolean;
var
KeyName: SOString;
begin
Result := False;
KeyName := TZ_KEY + Name;
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
if OpenKeyReadOnly(KeyName) then
begin
if ValueExists('IsObsolete') then
Result := ReadBool('IsObsolete');
CloseKey;
end;
finally
Free;
end;
end;
function TSuperTimeZone.GetTimeZoneInformation(Year: Word;
var TZI: TTimeZoneInformation): Boolean;
type
TRegistryTZI = packed record
Bias: LongInt;
StandardBias: LongInt;
DaylightBias: LongInt;
StandardChangeTime: TSystemTime;
DaylightChangeTime: TSystemTime;
end;
var
RegTZI: TRegistryTZI;
KeyName: SOString;
FirstYear, LastYear, ChangeYear: Word;
Retry: Boolean;
begin
FillChar(TZI, SizeOf(TZI), 0);
KeyName := TZ_KEY + Name;
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
if not KeyExists(KeyName) then
begin
Result := False;
Exit;
end;
ChangeYear := 0;
if OpenKeyReadOnly(KeyName + '\Dynamic DST') then
try
FirstYear := ReadInteger('FirstEntry');
LastYear := ReadInteger('LastEntry');
if (Year >= FirstYear) and (Year <= LastYear) then
ChangeYear := Year
else
ChangeYear := 0;
Retry := False;
repeat
while (ChangeYear > 0) and (not ValueExists(IntToStr(ChangeYear))) do
begin
Dec(ChangeYear);
if ChangeYear < FirstYear then
ChangeYear := 0;
end;
if ChangeYear > 0 then
begin
ReadBinaryData(IntToStr(ChangeYear), RegTZI, SizeOf(TRegistryTZI));
if RegTZI.DaylightChangeTime.wMonth > RegTZI.StandardChangeTime.wMonth then
begin
Dec(ChangeYear);
Retry := not Retry;
end;
end;
until not Retry;
finally
CloseKey;
end;
if (ChangeYear = 0) and OpenKeyReadOnly(KeyName) then
try
ReadBinaryData('TZI', RegTZI, SizeOf(TRegistryTZI));
finally
CloseKey;
end;
TZI.Bias := RegTZI.Bias;
TZI.StandardDate := RegTZI.StandardChangeTime;
TZI.StandardBias := RegTZI.StandardBias;
TZI.DaylightDate := RegTZI.DaylightChangeTime;
TZI.DaylightBias := RegTZI.DaylightBias;
Result := True;
finally
Free;
end;
end;
function TSuperTimeZone.TzSpecificLocalTimeToSystemTime(
const lpTimeZoneInformation: PTimeZoneInformation;
var lpLocalTime, lpUniversalTime: TSystemTime): BOOL;
var
ft: TFileTime;
lBias: LongInt;
t: Int64;
begin
Assert(lpTimeZoneInformation <> nil);
if (not SystemTimeToFileTime(lpLocalTime, ft)) then
begin
Result := False;
Exit;
end;
t := PInt64(@ft)^;
if (not GetTimezoneBias(lpTimeZoneInformation, @ft, True, @lBias)) then
begin
Result := False;
Exit;
end;
(* convert minutes to 100-nanoseconds-ticks *)
Inc(t, Int64(lBias) * 600000000);
PInt64(@ft)^ := t;
Result := FileTimeToSystemTime(ft, lpUniversalTime);
end;
function TSuperTimeZone.GetTimezoneBias(const pTZinfo: PTimeZoneInformation;
lpFileTime: PFileTime; islocal: Boolean; pBias: PLongint): Boolean;
var
bias: LongInt;
tzid: LongWord;
begin
bias := pTZinfo^.Bias;
tzid := CompTimeZoneID(pTZinfo, lpFileTime, islocal);
if( tzid = TIME_ZONE_ID_INVALID) then
begin
Result := False;
Exit;
end;
if (tzid = TIME_ZONE_ID_DAYLIGHT) then
Inc(bias, pTZinfo^.DaylightBias)
else if (tzid = TIME_ZONE_ID_STANDARD) then
Inc(bias, pTZinfo^.StandardBias);
pBias^ := bias;
Result := True;
end;
function TSuperTimeZone.CompTimeZoneID(const pTZinfo: PTimeZoneInformation;
lpFileTime: PFileTime; IsLocal: Boolean): LongWord;
var
Ret: Integer;
BeforeStandardDate, AfterDaylightDate: Boolean;
llTime: Int64;
SysTime: TSystemTime;
ftTemp: TFileTime;
begin
llTime := 0;
if (not GetDaylightDisabled) and (pTZinfo^.DaylightDate.wMonth <> 0) then
begin
(* if year is 0 then date is in day-of-week format, otherwise
* it's absolute date.
*)
if ((pTZinfo^.StandardDate.wMonth = 0) or
((pTZinfo^.StandardDate.wYear = 0) and
((pTZinfo^.StandardDate.wDay < 1) or
(pTZinfo^.StandardDate.wDay > 5) or
(pTZinfo^.DaylightDate.wDay < 1) or
(pTZinfo^.DaylightDate.wDay > 5)))) then
begin
SetLastError(ERROR_INVALID_PARAMETER);
Result := TIME_ZONE_ID_INVALID;
Exit;
end;
if (not IsLocal) then
begin
llTime := PInt64(lpFileTime)^;
Dec(llTime, Int64(pTZinfo^.Bias + pTZinfo^.DaylightBias) * 600000000);
PInt64(@ftTemp)^ := llTime;
lpFileTime := @ftTemp;
end;
FileTimeToSystemTime(lpFileTime^, SysTime);
(* check for daylight savings *)
Ret := DayLightCompareDate(@SysTime, @pTZinfo^.StandardDate);
if (Ret = -2) then
begin
Result := TIME_ZONE_ID_INVALID;
Exit;
end;
BeforeStandardDate := Ret < 0;
if (not IsLocal) then
begin
Dec(llTime, Int64(pTZinfo^.StandardBias - pTZinfo^.DaylightBias) * 600000000);
PInt64(@ftTemp)^ := llTime;
FileTimeToSystemTime(lpFileTime^, SysTime);
end;
Ret := DayLightCompareDate(@SysTime, @pTZinfo^.DaylightDate);
if (Ret = -2) then
begin
Result := TIME_ZONE_ID_INVALID;
Exit;
end;
AfterDaylightDate := Ret >= 0;
Result := TIME_ZONE_ID_STANDARD;
if pTZinfo^.DaylightDate.wMonth < pTZinfo^.StandardDate.wMonth then
begin
(* Northern hemisphere *)
if BeforeStandardDate and AfterDaylightDate then
Result := TIME_ZONE_ID_DAYLIGHT;
end
else
begin
(* Down south *)
if BeforeStandardDate or AfterDaylightDate then
Result := TIME_ZONE_ID_DAYLIGHT;
end;
end
else
(* No transition date *)
Result := TIME_ZONE_ID_UNKNOWN;
end;
function TSuperTimeZone.DayLightCompareDate(const date, compareDate: PSystemTime): Integer;
var
limit_day, dayinsecs, weekofmonth: Integer;
First: Word;
begin
if (date^.wMonth < compareDate^.wMonth) then
begin
Result := -1; (* We are in a month before the date limit. *)
Exit;
end;
if (date^.wMonth > compareDate^.wMonth) then
begin
Result := 1; (* We are in a month after the date limit. *)
Exit;
end;
(* if year is 0 then date is in day-of-week format, otherwise
* it's absolute date.
*)
if (compareDate^.wYear = 0) then
begin
(* compareDate.wDay is interpreted as number of the week in the month
* 5 means: the last week in the month *)
weekofmonth := compareDate^.wDay;
(* calculate the day of the first DayOfWeek in the month *)
First := (6 + compareDate^.wDayOfWeek - date^.wDayOfWeek + date^.wDay) mod 7 + 1;
limit_day := First + 7 * (weekofmonth - 1);
(* check needed for the 5th weekday of the month *)
if (limit_day > MonthDays[(date^.wMonth=2) and IsLeapYear(date^.wYear)][date^.wMonth]) then
Dec(limit_day, 7);
end
else
limit_day := compareDate^.wDay;
(* convert to seconds *)
limit_day := ((limit_day * 24 + compareDate^.wHour) * 60 + compareDate^.wMinute ) * 60;
dayinsecs := ((date^.wDay * 24 + date^.wHour) * 60 + date^.wMinute ) * 60 + date^.wSecond;
(* and compare *)
if dayinsecs < limit_day then
Result := -1
else if dayinsecs > limit_day then
Result := 1
else
Result := 0; (* date is equal to the date limit. *)
end;
function TSuperTimeZone.SystemTimeToTzSpecificLocalTime(
const lpTimeZoneInformation: PTimeZoneInformation;
var lpUniversalTime, lpLocalTime: TSystemTime): BOOL;
var
ft: TFileTime;
lBias: LongInt;
llTime: Int64;
begin
Assert(lpTimeZoneInformation <> nil);
if (not SystemTimeToFileTime(lpUniversalTime, ft)) then
begin
Result := False;
Exit;
end;
llTime := PInt64(@ft)^;
if (not GetTimezoneBias(lpTimeZoneInformation, @ft, False, @lBias)) then
begin
Result := False;
Exit;
end;
(* convert minutes to 100-nanoseconds-ticks *)
Dec(llTime, Int64(lBias) * 600000000);
PInt64(@ft)^ := llTime;
Result := FileTimeToSystemTime(ft, lpLocalTime);
end;
class function TSuperTimeZone.ParseISO8601Date(const ISO8601Date: SOString;
var st: TSystemTime; var dayofyear: Integer; var week: Word;
var bias: Integer; var havetz, havedate: Boolean): Boolean;
function get(var v: Word; c: SOChar): Boolean; {$IFDEF HAVE_INLINE} inline; {$ENDIF}
begin
if (c < #256) and (AnsiChar(c) in ['0' .. '9']) then
begin
Result := True;
v := v * 10 + Ord(c) - Ord('0');
end
else
Result := False;
end;
type
TState = (stStart, stYear, stMonth, stWeek, stWeekDay, stDay, stDayOfYear,
stHour, stMin, stSec, stMs, stUTC, stGMTH, stGMTM, stGMTend, stEnd);
TPerhaps = (yes, no, perhaps);
var
p: PSOChar;
sep: TPerhaps;
state: TState;
pos, v: Word;
inctz: Boolean;
label
error;
begin
p := PSOChar(ISO8601Date);
sep := perhaps;
state := stStart;
pos := 0;
inctz := False;
FillChar(st, SizeOf(st), 0);
dayofyear := 0;
week := 0;
bias := 0;
havedate := True;
havetz := False;
while True do
case state of
stStart:
case p^ of
'0' .. '9':
state := stYear;
'T', 't':
begin
state := stHour;
pos := 0;
Inc(p);
havedate := False;
end;
else
goto error;
end;
stYear:
case pos of
0 .. 1, 3:
if get(st.wYear, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
2:
case p^ of
'0' .. '9':
begin
st.wYear := st.wYear * 10 + Ord(p^) - Ord('0');
Inc(pos);
Inc(p);
end;
':':
begin
havedate := False;
st.wHour := st.wYear;
st.wYear := 0;
Inc(p);
pos := 0;
state := stMin;
sep := yes;
end;
else
goto error;
end;
4:
case p^ of
'-':
begin
pos := 0;
Inc(p);
sep := yes;
state := stMonth;
end;
'0' .. '9':
begin
sep := no;
pos := 0;
state := stMonth;
end;
'W', 'w':
begin
pos := 0;
Inc(p);
state := stWeek;
end;
'T', 't', ' ':
begin
state := stHour;
pos := 0;
Inc(p);
st.wMonth := 1;
st.wDay := 1;
end;
#0:
begin
st.wMonth := 1;
st.wDay := 1;
state := stEnd;
end;
else
goto error;
end;
end;
stMonth:
case pos of
0:
case p^ of
'0' .. '9':
begin
st.wMonth := Ord(p^) - Ord('0');
Inc(pos);
Inc(p);
end;
'W', 'w':
begin
pos := 0;
Inc(p);
state := stWeek;
end;
else
goto error;
end;
1:
if get(st.wMonth, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
2:
case p^ of
'-':
if (sep in [yes, perhaps]) then
begin
pos := 0;
Inc(p);
state := stDay;
sep := yes;
end
else
goto error;
'0' .. '9':
if sep in [no, perhaps] then
begin
pos := 0;
state := stDay;
sep := no;
end
else
begin
dayofyear := st.wMonth * 10 + Ord(p^) - Ord('0');
st.wMonth := 0;
Inc(p);
pos := 3;
state := stDayOfYear;
end;
'T', 't', ' ':
begin
state := stHour;
pos := 0;
Inc(p);
st.wDay := 1;
end;
#0:
begin
st.wDay := 1;
state := stEnd;
end;
else
goto error;
end;
end;
stDay:
case pos of
0:
if get(st.wDay, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
1:
if get(st.wDay, p^) then
begin
Inc(pos);
Inc(p);
end
else if sep in [no, perhaps] then
begin
dayofyear := st.wMonth * 10 + st.wDay;
st.wDay := 0;
st.wMonth := 0;
state := stDayOfYear;
end
else
goto error;
2:
case p^ of
'T', 't', ' ':
begin
pos := 0;
Inc(p);
state := stHour;
end;
#0:
state := stEnd;
else
goto error;
end;
end;
stDayOfYear:
begin
if (dayofyear <= 0) then
goto error;
case p^ of
'T', 't', ' ':
begin
pos := 0;
Inc(p);
state := stHour;
end;
#0:
state := stEnd;
else
goto error;
end;
end;
stWeek:
begin
case pos of
0 .. 1:
if get(week, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
2:
case p^ of
'-':
if (sep in [yes, perhaps]) then
begin
Inc(p);
state := stWeekDay;
sep := yes;
end
else
goto error;
'1' .. '7':
if sep in [no, perhaps] then
begin
state := stWeekDay;
sep := no;
end
else
goto error;
else
goto error;
end;
end;
end;
stWeekDay:
begin
if (week > 0) and get(st.wDayOfWeek, p^) then
begin
Inc(p);
v := st.wYear - 1;
v := ((v * 365) + (v div 4) - (v div 100) + (v div 400)) mod 7 + 1;
dayofyear := (st.wDayOfWeek - v) + ((week) * 7) + 1;
if v <= 4 then
Dec(dayofyear, 7);
case p^ of
'T', 't', ' ':
begin
pos := 0;
Inc(p);
state := stHour;
end;
#0:
state := stEnd;
else
goto error;
end;
end
else
goto error;
end;
stHour:
case pos of
0:
case p^ of
'0' .. '9':
if get(st.wHour, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
'-':
begin
Inc(p);
state := stMin;
end;
else
goto error;
end;
1:
if get(st.wHour, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
2:
case p^ of
':':
if sep in [yes, perhaps] then
begin
sep := yes;
pos := 0;
Inc(p);
state := stMin;
end
else
goto error;
',', '.':
begin
Inc(p);
state := stMs;
end;
'+':
if havedate then
begin
state := stGMTH;
pos := 0;
v := 0;
Inc(p);
end
else
goto error;
'-':
if havedate then
begin
state := stGMTH;
pos := 0;
v := 0;
Inc(p);
inctz := True;
end
else
goto error;
'Z', 'z':
if havedate then
state := stUTC
else
goto error;
'0' .. '9':
if sep in [no, perhaps] then
begin
pos := 0;
state := stMin;
sep := no;
end
else
goto error;
#0:
state := stEnd;
else
goto error;
end;
end;
stMin:
case pos of
0:
case p^ of
'0' .. '9':
if get(st.wMinute, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
'-':
begin
Inc(p);
state := stSec;
end;
else
goto error;
end;
1:
if get(st.wMinute, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
2:
case p^ of
':':
if sep in [yes, perhaps] then
begin
pos := 0;
Inc(p);
state := stSec;
sep := yes;
end
else
goto error;
',', '.':
begin
Inc(p);
state := stMs;
end;
'+':
if havedate then
begin
state := stGMTH;
pos := 0;
v := 0;
Inc(p);
end
else
goto error;
'-':
if havedate then
begin
state := stGMTH;
pos := 0;
v := 0;
Inc(p);
inctz := True;
end
else
goto error;
'Z', 'z':
if havedate then
state := stUTC
else
goto error;
'0' .. '9':
if sep in [no, perhaps] then
begin
pos := 0;
state := stSec;
end
else
goto error;
#0:
state := stEnd;
else
goto error;
end;
end;
stSec:
case pos of
0 .. 1:
if get(st.wSecond, p^) then
begin
Inc(pos);
Inc(p);
end
else
goto error;
2:
case p^ of
',', '.':
begin
Inc(p);
state := stMs;
end;
'+':
if havedate then
begin
state := stGMTH;
pos := 0;
v := 0;
Inc(p);
end
else
goto error;
'-':
if havedate then
begin
state := stGMTH;
pos := 0;
v := 0;
Inc(p);
inctz := True;
end
else
goto error;
'Z', 'z':
if havedate then
state := stUTC
else
goto error;
#0:
state := stEnd;
else
goto error;
end;
end;
stMs:
case p^ of
'0' .. '9':
begin
st.wMilliseconds := st.wMilliseconds * 10 + Ord(p^) - Ord('0');
Inc(p);
end;
'+':
if havedate then
begin
state := stGMTH;
pos := 0;
v := 0;
Inc(p);
end
else
goto error;
'-':
if havedate then
begin
state := stGMTH;
pos := 0;
v := 0;
Inc(p);
inctz := True;
end
else
goto error;
'Z', 'z':
if havedate then
state := stUTC
else
goto error;
#0:
state := stEnd;
else
goto error;
end;
stUTC: // = GMT 0
begin
havetz := True;
Inc(p);
if p^ = #0 then
Break
else
goto error;
end;
stGMTH:
begin
havetz := True;
case pos of
0 .. 1:
if get(v, p^) then
begin
Inc(p);
Inc(pos);
end
else
goto error;
2:
begin
bias := v * 60;
case p^ of
':': // if sep in [yes, perhaps] then
begin
state := stGMTM;
Inc(p);
pos := 0;
v := 0;
sep := yes;
end; // else goto error;
'0' .. '9':
// if sep in [no, perhaps] then
begin
state := stGMTM;
pos := 1;
sep := no;
Inc(p);
v := Ord(p^) - Ord('0');
end; // else goto error;
#0:
state := stGMTend;
else
goto error;
end;
end;
end;
end;
stGMTM:
case pos of
0 .. 1:
if get(v, p^) then
begin
Inc(p);
Inc(pos);
end
else
goto error;
2:
case p^ of
#0:
begin
state := stGMTend;
Inc(bias, v);
end;
else
goto error;
end;
end;
stGMTend:
begin
if not inctz then
bias := -bias;
Break;
end;
stEnd:
begin
Break;
end;
end;
if (st.wHour >= 24) or (st.wMinute >= 60) or (st.wSecond >= 60) or
(st.wMilliseconds >= 1000) or (week > 53) then
goto error;
Result := True;
Exit;
error:
Result := False;
end;
end.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/afrusrsc-superobject.git
git@api.gitlife.ru:oschina-mirror/afrusrsc-superobject.git
oschina-mirror
afrusrsc-superobject
afrusrsc-superobject
master