瀏覽代碼

* unix timezone optimizations

git-svn-id: trunk@47321 -
ondrej 4 年之前
父節點
當前提交
3ee2097f1a
共有 3 個文件被更改,包括 94 次插入61 次删除
  1. 8 15
      rtl/unix/sysutils.pp
  2. 70 13
      rtl/unix/timezone.inc
  3. 16 33
      rtl/unix/unix.pp

+ 8 - 15
rtl/unix/sysutils.pp

@@ -1648,22 +1648,15 @@ var
 begin
   DecodeDate(DateTime, Year, Month, Day);
   DecodeTime(DateTime, Hour, Minute, Second, MilliSecond);
-  if InputIsUTC then
-    UnixTime:=UniversalToEpoch(Year, Month, Day, Hour, Minute, Second)
-  else
-    UnixTime:=LocalToEpoch(Year, Month, Day, Hour, Minute, Second);
-  { check if time is in current global Tzinfo }
-  lTzinfo:=Tzinfo;
-  if (lTzinfo.validsince<=UnixTime) and (UnixTime<lTzinfo.validuntil) then
-  begin
-    Result:=True;
+  UnixTime:=UniversalToEpoch(Year, Month, Day, Hour, Minute, Second);
+
+  {$if declared(GetLocalTimezone)}
+  GetLocalTimeOffset:=GetLocalTimezone(UnixTime,InputIsUTC,lTZInfo);
+  if GetLocalTimeOffset then
     Offset:=-lTZInfo.seconds div 60;
-  end else
-  begin
-    Result:=GetLocalTimezone(UnixTime,True,lTZInfo);
-    if Result then
-      Offset:=-lTZInfo.seconds div 60;
-  end;
+  {$else}
+  GetLocalTimeOffset:=False;
+  {$endif}
 end;
 
 {$ifdef android}

+ 70 - 13
rtl/unix/timezone.inc

@@ -43,7 +43,24 @@ var
 
 function find_transition(timer:longint;timerIsUTC:Boolean;var trans_start,trans_end:longint):pttinfo;
 var
-  i : longint;
+  i,L,R,CompareRes : longint;
+
+  function DoCompare: longint;
+  var
+    timerUTC: LongInt;
+  begin
+    if not timerIsUTC then
+      timerUTC:=timer-types[type_idxs[i-1]].offset
+    else
+      timerUTC:=timer;
+    if timerUTC<transitions[i-1] then
+      Exit(-1)
+    else
+    if timerUTC>=transitions[i] then
+      Exit(1)
+    else
+      Exit(0);
+  end;
 begin
   if (num_transitions=0) or (timer<transitions[0]) then
    begin
@@ -58,15 +75,22 @@ begin
    end
   else
    begin
-     i:=1;
-     while i<=num_transitions-1 do
-       begin
-         case timerIsUTC of
-           True: if (timer<transitions[i]) then break;
-           False: if (timer<transitions[i]+types[type_idxs[i-1]].offset) then break;
-         end;
-         inc(i);
-       end;
+      // Use binary search.
+      L := 1;
+      R := num_transitions-1;
+      while (L<=R) do
+      begin
+        I := L + (R - L) div 2;
+        CompareRes := DoCompare;
+        if (CompareRes>0) then
+          L := I+1
+        else begin
+          R := I-1;
+          if (CompareRes=0) then
+             L:=I; // break cycle
+        end;
+      end;
+
      trans_start:=transitions[i-1];
      trans_end:=transitions[i];
      i:=type_idxs[i-1];
@@ -128,7 +152,17 @@ function GetLocalTimezone(timer:cint;timerIsUTC:Boolean;var ATZInfo:TTZInfo):Boo
 var
   info: pttinfo;
   trans_start,trans_end: longint;
+  timerUTC: cint;
 begin
+  { check if time is in current global Tzinfo }
+  ATZInfo:=CurrentTZinfo[InterlockedExchangeAdd(CurrentTZindex, 0)];
+  if not timerIsUTC then
+    timerUTC:=timer-ATZInfo.seconds
+  else
+    timerUTC:=timer;
+  if (ATZInfo.validsince<=timerUTC) and (timerUTC<ATZInfo.validuntil) then
+    Exit(True);
+
   LockTZInfo;
   info:=find_transition(timer,timerIsUTC,trans_start,trans_end);
   GetLocalTimezone:=assigned(info);
@@ -141,7 +175,21 @@ function GetLocalTimezone(timer:cint;timerIsUTC:Boolean;var ATZInfo:TTZInfo;var
 var
   info: pttinfo;
   trans_start,trans_end: longint;
+  timerUTC: cint;
 begin
+  { check if time is in current global Tzinfo }
+  ATZInfo:=CurrentTZinfo[InterlockedExchangeAdd(CurrentTZindex, 0)];
+  if not timerIsUTC then
+    timerUTC:=timer-ATZInfo.seconds
+  else
+    timerUTC:=timer;
+  if (ATZInfo.validsince<=timerUTC) and (timerUTC<ATZInfo.validuntil) then
+    begin
+    ATZInfoEx:=TZInfoEx;
+    Exit(True);
+    end;
+
+  { not current - search through all }
   LockTZInfo;
   info:=find_transition(timer,timerIsUTC,trans_start,trans_end);
   GetLocalTimezone:=assigned(info);
@@ -178,7 +226,7 @@ begin
     TimeZoneDir:=TimeZoneDir+'/';
 end;
 
-procedure ReadTimezoneFile(fn:shortstring);
+function ReadTimezoneFile(fn:string) : Boolean;
 
   procedure decode(var l:longint);
   var
@@ -247,17 +295,24 @@ var
   i      : longint;
   chars  : longint;
 begin
+  LockTZInfo;
   if fn='' then
    fn:='localtime';
   if fn[1]<>'/' then
     fn:=TimeZoneDir+fn;
   f:=fpopen(fn,Open_RdOnly);
   if f<0 then
-   exit;
+  begin
+   UnlockTZInfo;
+   exit(False);
+  end;
   bufptr := @buf[bufsize-1]+1;
   i:=readbuf(tzhead,sizeof(tzhead));
   if i<>sizeof(tzhead) then
-   exit;
+  begin
+   UnlockTZInfo;
+   exit(False);
+  end;
   decode(tzhead.tzh_timecnt);
   decode(tzhead.tzh_typecnt);
   decode(tzhead.tzh_charcnt);
@@ -308,6 +363,8 @@ begin
    types[i].isgmt:=byte(readbufbyte<>0);
 
   fpclose(f);
+  ReadTimezoneFile:=True;
+  UnlockTZInfo;
 end;
 
 Const

+ 16 - 33
rtl/unix/unix.pp

@@ -91,7 +91,7 @@ type
 function GetLocalTimezone(timer:cint;timerIsUTC:Boolean;var ATZInfo:TTZInfo;var ATZInfoEx:TTZInfoEx):Boolean;
 function GetLocalTimezone(timer:cint;timerIsUTC:Boolean;var ATZInfo:TTZInfo):Boolean;
 procedure RefreshTZInfo;
-procedure ReadTimezoneFile(fn:string);
+function  ReadTimezoneFile(fn:string) : Boolean;
 function  GetTimezoneFile:string;
 Procedure ReReadLocalTime;
 {$ENDIF}
@@ -299,22 +299,13 @@ Procedure EpochToLocal(epoch:Int64;var year,month,day,hour,minute,second:Word);
 }
 Var
   lTZInfo: TTZInfo;
-  lseconds: LongInt;
 Begin
-  { check if time is in current global Tzinfo }
-  lTZInfo:=TZInfo;
-  lseconds:=lTZInfo.seconds;
-  if (lTZInfo.validsince<=epoch) and (epoch<lTZInfo.validuntil) then
-    inc(Epoch,lseconds)
-  else
-  begin
-    {$if declared(GetLocalTimezone)}
-    if GetLocalTimezone(epoch,true,lTZInfo) then
-      inc(Epoch,lTZInfo.seconds)
-    else { fallback }
-    {$endif}
-      inc(Epoch,lseconds);
-  end;
+  {$if declared(GetLocalTimezone)}
+  if GetLocalTimezone(epoch,true,lTZInfo) then
+    inc(Epoch,lTZInfo.seconds)
+  else { fallback }
+  {$endif}
+    inc(Epoch,TZInfo.seconds);
 
   EpochToUniversal(epoch,year,month,day,hour,minute,second);
 End;
@@ -342,24 +333,16 @@ Function LocalToEpoch(year,month,day,hour,minute,second:Word):Int64;
 }
 Var
   lTZInfo: TTZInfo;
-  UniversalEpoch: Int64;
-  lseconds: LongInt;
+  LocalEpoch: Int64;
 Begin
-  UniversalEpoch:=UniversalToEpoch(year,month,day,hour,minute,second);
-  { check if time is in current global Tzinfo }
-  lTZInfo:=TZInfo;
-  lseconds:=lTZInfo.seconds;
-  if (lTZInfo.validsince<=UniversalEpoch-lTZInfo.seconds) and (UniversalEpoch-lTZInfo.seconds<lTZInfo.validuntil) then
-    LocalToEpoch:=UniversalEpoch-lseconds
-  else
-  begin
-    {$if declared(GetLocalTimezone)}
-    if GetLocalTimezone(UniversalEpoch,false,lTZInfo) then
-      LocalToEpoch:=UniversalEpoch-lTZInfo.seconds
-    else { fallback }
-    {$endif}
-      LocalToEpoch:=UniversalEpoch-lseconds;
-  end;
+  LocalEpoch:=UniversalToEpoch(year,month,day,hour,minute,second);
+
+  {$if declared(GetLocalTimezone)}
+  if GetLocalTimezone(LocalEpoch,false,lTZInfo) then
+    LocalToEpoch:=LocalEpoch-lTZInfo.seconds
+  else { fallback }
+  {$endif}
+    LocalToEpoch:=LocalEpoch-TZInfo.seconds;
 End;
 
 Function UniversalToEpoch(year,month,day,hour,minute,second:Word):Int64;