Пишу для тех, кто будет так же как я тупить. Если взять узко получение сведений о часовых поясах из ОС Windows, то примеры вроде бы и есть в сети, но все они связаны с работой GetTimeZoneInformation. Lazarus знает эту функцию и тип данных ею передаваемый.
Список описанных в реестре временных зон читаем так
Код: Выделить всё
{$IFDEF WINDOWS}
cbTimeList.Clear;
reg := TRegistry.Create;
reg.RootKey := HKEY_LOCAL_MACHINE;
reg.LazyWrite := false;
r := reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones');
//В сети много где пишут другой путь, наверно в разных версиях Win по разному все.
if r and reg.HasSubKeys then
begin
ts := TStringList.Create;
reg.GetKeyNames(ts);
reg.CloseKey;
for i := 0 to ts.Count -1 do
begin
reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\' + ts.Strings[i]);
sTmp:=reg.ReadString('Display');
sTmp:=WinCPToUTF8(sTmp);
cbTimeList.Items.Add(sTmp);
reg.CloseKey;
end;
ts.Free;
end
else
reg.CloseKey;
reg.free;
{$ELSE}
cbTimeList.Clear;
{$ENDIF}
Список есть, дальше что? Нужно как то получить смещение и сведения о зиме/лете во времени.
Когда я забивал поиск по теме TimeZoneInformation то мне все время выдавалась страница MSDN с описанием того, что и так уже есть в Lazarus и примеры работы с функцией получения своей временной зоны через GetTimeZoneInformation. Описываемой записью вида:
Код: Выделить всё
TIME_ZONE_INFORMATION = record
Bias : LONG;
StandardName : array[0..31] of WCHAR;
StandardDate : SYSTEMTIME;
StandardBias : LONG;
DaylightName : array[0..31] of WCHAR;
DaylightDate : SYSTEMTIME;
DaylightBias : LONG;
end;
Логично предположить, что в реестре бинарное поле TZI(из ветки списка зон) хранящее сведения о переводах времени имеет такой же формат. Но нет. Если коротко - я заколебался пытаться понять почему у меня нет перевода на лето/зиму в тех тестах где должно быть. Данные о датах просто не прописывались в переменную. Пока я случайно не наткнулся на иное описание касающееся именно реестра. Ну не умею я работать с MSDN мелкософта, там все косноязычно описано. Собственно моя проблема в том была, что поле TZI реестра имеет другую структура данных, не соответствующую WinApi функции. Оно в реестре короче по размеру.
Код: Выделить всё
_REG_TZI_FORMAT = record
Bias : LONG;
StandardBias : LONG;
DaylightBias : LONG;
StandardDate : SYSTEMTIME;
DaylightDate : SYSTEMTIME;
end;
Когда тип данных исправлен, все отлично работает и читается как в примере ниже.
Код: Выделить всё
procedure ....;
var
CityTimeDataList:TCollection....;
Item:T....Item;
reg :TRegistry;
tmpBiaseHour,
k :integer;
sTimeZoneName:String;
tziTmp:_REG_TZI_FORMAT;
tmpDateTimeDay,
tmpDateTimeStd:TDateTime;
begin
//....
//....
{$IFDEF WINDOWS}
reg := TRegistry.Create;
reg.RootKey := HKEY_LOCAL_MACHINE;
reg.LazyWrite := false;
for k := 0 to CityTimeDataList.Count -1 do
begin
Item :=CityTimeDataList.Items[k];
sTimeZoneName :=Item.AdditionalProperty.GetString('TimeZoneName', 'NULL');
if reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\' + sTimeZoneName) then
begin
reg.ReadBinaryData('TZI', tziTmp, SizeOf(tziTmp));
if (tziTmp.Bias<>0) then
tmpBiaseHour:=integer(tziTmp.Bias div -60)
else
tmpBiaseHour:=0;
if tziTmp.DaylightDate.wMonth<>0 then //сравнивать надо именно с месяцем
begin
tziTmp.DaylightDate.wYear:=DateUtils.YearOf(Now);
tziTmp.StandardDate.wYear:=DateUtils.YearOf(Now);
tmpDateTimeDay :=DateUtils.EncodeDateTime(tziTmp.DaylightDate.wYear,tziTmp.DaylightDate.wMonth,tziTmp.DaylightDate.wDay,tziTmp.DaylightDate.wHour,tziTmp.DaylightDate.wMinute,0,0);
tmpDateTimeStd :=DateUtils.EncodeDateTime(tziTmp.StandardDate.wYear,tziTmp.StandardDate.wMonth,tziTmp.StandardDate.wDay,tziTmp.StandardDate.wHour,tziTmp.StandardDate.wMinute,0,0);
if (DateUtils.CompareDate(now,tmpDateTimeDay)>=0)and(DateUtils.CompareDate(now,tmpDateTimeStd)<0) then
begin
//лето
if (tziTmp.DaylightBias<>0) then
tmpBiaseHour:=tmpBiaseHour+integer(tziTmp.DaylightBias div -60);
end
else begin
//зима
if (tziTmp.StandardBias<>0) then
tmpBiaseHour:=tmpBiaseHour+integer(tziTmp.StandardBias div -60);
end;
end;
Item.AdditionalProperty.SetValue('CurrentBiaseHour', tmpBiaseHour); //смещение в текущий момент для выбранного часового пояса
reg.CloseKey;
end
else begin
ThisApplication.SystemLog(RL_ERRORTEXT,format('Не найдена информация о применяемом в профиле часовом поясе "%s"',[sTimeZoneName]));
end;
end;//k
reg.free;
{$ELSE}
{$ENDIF}
end;