GetLocalTimeOffset: DateTime-aware overloads for Unix. Issue #35710

git-svn-id: trunk@47290 -
(cherry picked from commit 282aa0daa7)
This commit is contained in:
ondrej 2020-11-03 11:41:28 +00:00 committed by marcoonthegit
parent e62556e7f1
commit 0a2e59c243
4 changed files with 106 additions and 33 deletions

View File

@ -1671,8 +1671,26 @@ end;
function GetLocalTimeOffset(const DateTime: TDateTime; out Offset: Integer): Boolean;
var
Year, Month, Day, Hour, Minute, Second, MilliSecond: word;
UnixTime: Int64;
lc,lh: cint;
lTZInfo: TTZInfo;
begin
Result := False; // ToDo
DecodeDate(DateTime, Year, Month, Day);
DecodeTime(DateTime, Hour, Minute, Second, MilliSecond);
UnixTime:=LocalToEpoch(Year, Month, Day, Hour, Minute, Second);
{ check if time is in current global Tzinfo }
if (Tzinfo.validsince<UnixTime) and (UnixTime<Tzinfo.validuntil) then
begin
Result:=True;
Offset:=-TZInfo.seconds div 60;
end else
begin
Result:=GetLocalTimezone(UnixTime,lTZInfo,False);
if Result then
Offset:=-lTZInfo.seconds div 60;
end;
end;
{$ifdef android}

View File

@ -41,7 +41,7 @@ var
zone_names : pchar = Nil;
leaps : pleap = Nil;
function find_transition(timer:longint):pttinfo;
function find_transition(timer:longint;var trans_start,trans_end:longint):pttinfo;
var
i : longint;
begin
@ -52,6 +52,9 @@ begin
inc(i);
if (i=num_types) then
i:=0;
{ unknown transition boundaries }
trans_start:=low(trans_start);
trans_end:=high(trans_end);
end
else
begin
@ -62,65 +65,72 @@ begin
break;
inc(i);
end;
trans_start:=transitions[i-1];
trans_end:=transitions[i];
i:=type_idxs[i-1];
end;
find_transition:=@types[i];
end;
procedure GetLocalTimezone(timer:longint;var leap_correct,leap_hit:longint);
function GetLocalTimezone(timer:cint;var ATZInfo:TTZInfo;FullInfo:Boolean):Boolean;
var
info : pttinfo;
i : longint;
i,trans_start,trans_end : longint;
begin
{ reset }
TZDaylight:=false;
TZSeconds:=0;
TZName[false]:=nil;
TZName[true]:=nil;
leap_correct:=0;
leap_hit:=0;
ATZInfo.Daylight:=false;
ATZInfo.Seconds:=0;
ATZInfo.Name[false]:=nil;
ATZInfo.Name[true]:=nil;
ATZInfo.validsince:=0;
ATZInfo.validuntil:=0;
ATZInfo.leap_correct:=0;
ATZInfo.leap_hit:=0;
{ get info }
info:=find_transition(timer);
if not assigned(info) then
info:=find_transition(timer,trans_start,trans_end);
GetLocalTimezone:=assigned(info);
if not GetLocalTimezone then
exit;
TZDaylight:=info^.isdst;
TZSeconds:=info^.offset;
ATZInfo.validsince:=trans_start;
ATZInfo.validuntil:=trans_end;
ATZInfo.Daylight:=info^.isdst;
ATZInfo.Seconds:=info^.offset;
if not FullInfo then
Exit;
i:=0;
while (i<num_types) do
begin
tzname[types[i].isdst]:=@zone_names[types[i].idx];
ATZInfo.name[types[i].isdst]:=@zone_names[types[i].idx];
inc(i);
end;
tzname[info^.isdst]:=@zone_names[info^.idx];
ATZInfo.name[info^.isdst]:=@zone_names[info^.idx];
i:=num_leaps;
repeat
if i=0 then
exit;
dec(i);
until (timer>leaps[i].transition);
leap_correct:=leaps[i].change;
ATZInfo.leap_correct:=leaps[i].change;
if (timer=leaps[i].transition) and
(((i=0) and (leaps[i].change>0)) or
(leaps[i].change>leaps[i-1].change)) then
begin
leap_hit:=1;
ATZInfo.leap_hit:=1;
while (i>0) and
(leaps[i].transition=leaps[i-1].transition+1) and
(leaps[i].change=leaps[i-1].change+1) do
begin
inc(leap_hit);
inc(ATZInfo.leap_hit);
dec(i);
end;
end;
end;
procedure GetLocalTimezone(timer:longint);
var
lc,lh : longint;
procedure GetLocalTimezone(timer:cint);
begin
GetLocalTimezone(timer,lc,lh);
GetLocalTimezone(timer,Tzinfo,true);
end;
Const
@ -339,6 +349,7 @@ end;
procedure InitLocalTime;
begin
ReloadTzinfo:=@InitLocalTime;
ReadTimezoneFile(GetTimezoneFile);
GetLocalTimezone(fptime);
end;

View File

@ -16,7 +16,9 @@ Unit Unix;
Interface
Uses
BaseUnix,UnixType;
BaseUnix,UnixType,
UnixUtil // tzseconds
;
// If you deprecated new symbols, please annotate the version.
// this makes it easier to decide if they can already be removed.
@ -52,9 +54,10 @@ Const
{** Time/Date Handling **}
var
tzdaylight : boolean;
tzname : array[boolean] of pchar;
function Gettzdaylight : boolean;
function Gettzname(const b : boolean) : pchar;
property tzdaylight : boolean read Gettzdaylight;
property tzname[b : boolean] : pchar read Gettzname;
{************ Procedure/Functions ************}
@ -66,7 +69,7 @@ var
// it doesn't (yet) work for.
{ timezone support }
procedure GetLocalTimezone(timer:cint;var leap_correct,leap_hit:cint);
function GetLocalTimezone(timer:cint;var ATZInfo:TTZInfo;FullInfo:Boolean):Boolean;
procedure GetLocalTimezone(timer:cint);
procedure ReadTimezoneFile(fn:string);
function GetTimezoneFile:string;
@ -141,10 +144,10 @@ Function FSearch (const path:UnicodeString;dirlist:UnicodeString):UnicodeStrin
Implementation
Uses
UnixUtil // tzseconds
{$ifndef FPC_USE_LIBC},Syscall{$endif}
;
{$ifndef FPC_USE_LIBC}
Uses
Syscall;
{$endif}
{$i unxovl.inc}
@ -157,6 +160,20 @@ Uses
Function getenv(name:string):Pchar; external name 'FPC_SYSC_FPGETENV';
{******************************************************************************
timezone support
******************************************************************************}
function Gettzdaylight : boolean;
begin
Gettzdaylight:=Tzinfo.daylight;
end;
function Gettzname(const b : boolean) : pchar;
begin
Gettzname:=Tzinfo.name[b];
end;
{******************************************************************************
Process related calls
******************************************************************************}

View File

@ -27,8 +27,25 @@ unit unixutil;
interface
uses BaseUnix;
type
TTZInfo = record
daylight : boolean;
name : array[boolean] of pchar;
seconds : Longint; // difference from UTC
validsince : int64; // UTC timestamp
validuntil : int64; // UTC timestamp
leap_correct : longint;
leap_hit : longint;
end;
var
Tzseconds : Longint;
Tzinfo : TTZInfo;
ReloadTzinfo : TProcedure;
Function GetTzseconds : Longint;
property Tzseconds : Longint read GetTzseconds;
Function StringToPPChar(S: PChar;ReserveEntries:integer):ppchar;
Function StringToPPChar(Var S:RawByteString;ReserveEntries:integer):ppchar;
@ -40,6 +57,16 @@ Function GregorianToJulian(Year,Month,Day:Longint):LongInt; deprecated 'use Date
implementation
Function GetTzseconds : Longint;
var
curtime: time_t;
begin
curtime:=fptime;
if assigned(ReloadTzinfo) and ((curtime<Tzinfo.validsince+Tzinfo.seconds) or (curtime>Tzinfo.validuntil+Tzinfo.seconds)) then
ReloadTzinfo;
GetTzseconds:=Tzinfo.seconds;
end;
function ArrayStringToPPchar(const S:Array of RawByteString;reserveentries:Longint):ppchar; // const ?
// Extra allocate reserveentries pchar's at the beginning (default param=0 after 1.0.x ?)
// Note: for internal use by skilled programmers only