瀏覽代碼

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

git-svn-id: trunk@47290 -
ondrej 4 年之前
父節點
當前提交
282aa0daa7
共有 4 個文件被更改,包括 106 次插入33 次删除
  1. 19 1
      rtl/unix/sysutils.pp
  2. 33 22
      rtl/unix/timezone.inc
  3. 26 9
      rtl/unix/unix.pp
  4. 28 1
      rtl/unix/unixutil.pp

+ 19 - 1
rtl/unix/sysutils.pp

@@ -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}

+ 33 - 22
rtl/unix/timezone.inc

@@ -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;

+ 26 - 9
rtl/unix/unix.pp

@@ -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
 ******************************************************************************}

+ 28 - 1
rtl/unix/unixutil.pp

@@ -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;
@@ -41,6 +58,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