2
0
Эх сурвалжийг харах

LocalToEpoch, EpochToLocal: fix for arbitrary datetime

git-svn-id: trunk@47291 -
ondrej 4 жил өмнө
parent
commit
f4cff81881

+ 1 - 1
packages/libxml/src/xmlxsdparser.pas

@@ -14,7 +14,7 @@ interface
 
 uses
   {$IFDEF MSWINDOWS}windows,{$ENDIF}
-  {$IFDEF UNIX}unixutil,{$ENDIF}
+  {$IFDEF UNIX}unix,{$ENDIF}
   sysutils,
   dateutils,
   math,

+ 1 - 85
rtl/unix/dos.pp

@@ -57,7 +57,7 @@ Function AddDisk(const path:string) : byte; platform;
 Implementation
 
 Uses
-  UnixUtil, // tzSeconds
+  UnixUtil,
   Strings,
   Unix,
   {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF};
@@ -89,90 +89,6 @@ type
                         --- Info / Date / Time ---
 ******************************************************************************}
 
-
-Const
-{Date Calculation}
-  C1970 = 2440588;
-  D0    = 1461;
-  D1    = 146097;
-  D2    = 1721119;
-type
-  GTRec = packed Record
-    Year,
-    Month,
-    MDay,
-    WDay,
-    Hour,
-    Minute,
-    Second : Word;
-  End;
-
-Function GregorianToJulian(Year,Month,Day:Longint):LongInt;
-Var
-  Century,XYear: LongInt;
-Begin
-  If Month<=2 Then
-   Begin
-     Dec(Year);
-     Inc(Month,12);
-   End;
-  Dec(Month,3);
-  Century:=(longint(Year Div 100)*D1) shr 2;
-  XYear:=(longint(Year Mod 100)*D0) shr 2;
-  GregorianToJulian:=((((Month*153)+2) div 5)+Day)+D2+XYear+Century;
-End;
-
-
-Function LocalToEpoch(year,month,day,hour,minute,second:Word):Longint;
-{
-  Transforms local time (year,month,day,hour,minutes,second) to Epoch time
-   (seconds since 00:00, january 1 1970, corrected for local time zone)
-}
-Begin
-  LocalToEpoch:=((GregorianToJulian(Year,Month,Day)-c1970)*86400)+
-                (LongInt(Hour)*3600)+(Longint(Minute)*60)+Second-TZSeconds;
-End;
-
-Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
-Var
-  YYear,XYear,Temp,TempMonth : LongInt;
-Begin
-  Temp:=((JulianDN-D2) shl 2)-1;
-  JulianDN:=Temp Div D1;
-  XYear:=(Temp Mod D1) or 3;
-  YYear:=(XYear Div D0);
-  Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
-  Day:=((Temp Mod 153)+5) Div 5;
-  TempMonth:=Temp Div 153;
-  If TempMonth>=10 Then
-   Begin
-     inc(YYear);
-     dec(TempMonth,12);
-   End;
-  inc(TempMonth,3);
-  Month := TempMonth;
-  Year:=YYear+(JulianDN*100);
-end;
-
-Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
-{
-  Transforms Epoch time into local time (hour, minute,seconds)
-}
-Var
-  DateNum: LongInt;
-Begin
-  inc(Epoch,TZSeconds);
-  Datenum:=(Epoch Div 86400) + c1970;
-  JulianToGregorian(DateNum,Year,Month,day);
-  Epoch:=Abs(Epoch Mod 86400);
-  Hour:=Epoch Div 3600;
-  Epoch:=Epoch Mod 3600;
-  Minute:=Epoch Div 60;
-  Second:=Epoch Mod 60;
-End;
-
-
-
 Function DosVersion:Word;
 Var
   Buffer : Array[0..255] of Char;

+ 1 - 51
rtl/unix/sysutils.pp

@@ -293,55 +293,6 @@ procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
 { Include SysCreateGUID function }
 {$i suuid.inc}
 
-Const
-{Date Translation}
-  C1970=2440588;
-  D0   =   1461;
-  D1   = 146097;
-  D2   =1721119;
-
-
-Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
-Var
-  YYear,XYear,Temp,TempMonth : LongInt;
-Begin
-  Temp:=((JulianDN-D2) shl 2)-1;
-  JulianDN:=Temp Div D1;
-  XYear:=(Temp Mod D1) or 3;
-  YYear:=(XYear Div D0);
-  Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
-  Day:=((Temp Mod 153)+5) Div 5;
-  TempMonth:=Temp Div 153;
-  If TempMonth>=10 Then
-   Begin
-     inc(YYear);
-     dec(TempMonth,12);
-   End;
-  inc(TempMonth,3);
-  Month := TempMonth;
-  Year:=YYear+(JulianDN*100);
-end;
-
-
-
-Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
-{
-  Transforms Epoch time into local time (hour, minute,seconds)
-}
-Var
-  DateNum: LongInt;
-Begin
-  inc(Epoch,TZSeconds);
-  Datenum:=(Epoch Div 86400) + c1970;
-  JulianToGregorian(DateNum,Year,Month,day);
-  Epoch:=Abs(Epoch Mod 86400);
-  Hour:=Epoch Div 3600;
-  Epoch:=Epoch Mod 3600;
-  Minute:=Epoch Div 60;
-  Second:=Epoch Mod 60;
-End;
-
-
 function GetTickCount64: QWord;
 var
   tp: TTimeVal;
@@ -1674,7 +1625,6 @@ function GetLocalTimeOffset(const DateTime: TDateTime; out Offset: Integer): Boo
 var
   Year, Month, Day, Hour, Minute, Second, MilliSecond: word;
   UnixTime: Int64;
-  lc,lh: cint;
   lTZInfo: TTZInfo;
 begin
   DecodeDate(DateTime, Year, Month, Day);
@@ -1687,7 +1637,7 @@ begin
     Offset:=-TZInfo.seconds div 60;
   end else
   begin
-    Result:=GetLocalTimezone(UnixTime,lTZInfo,False);
+    Result:=GetLocalTimezone(UnixTime,True,lTZInfo,False);
     if Result then
       Offset:=-lTZInfo.seconds div 60;
   end;

+ 10 - 9
rtl/unix/timezone.inc

@@ -41,7 +41,7 @@ var
   zone_names   : pchar = Nil;
   leaps        : pleap = Nil;
 
-function find_transition(timer:longint;var trans_start,trans_end:longint):pttinfo;
+function find_transition(timer:longint;timerIsUTC:Boolean;var trans_start,trans_end:longint):pttinfo;
 var
   i : longint;
 begin
@@ -61,8 +61,10 @@ begin
      i:=1;
      while i<=num_transitions-1 do
        begin
-         if (timer<transitions[i]) then
-           break;
+         case timerIsUTC of
+           True: if (timer<transitions[i]) then break;
+           False: if (timer<transitions[i]+types[type_idxs[i]].offset) then break;
+         end;
          inc(i);
        end;
      trans_start:=transitions[i-1];
@@ -73,7 +75,7 @@ begin
 end;
 
 
-function GetLocalTimezone(timer:cint;var ATZInfo:TTZInfo;FullInfo:Boolean):Boolean;
+function GetLocalTimezone(timer:cint;timerIsUTC:Boolean;var ATZInfo:TTZInfo;FullInfo:Boolean):Boolean;
 var
   info : pttinfo;
   i,trans_start,trans_end : longint;
@@ -88,7 +90,7 @@ begin
   ATZInfo.leap_correct:=0;
   ATZInfo.leap_hit:=0;
 { get info }
-  info:=find_transition(timer,trans_start,trans_end);
+  info:=find_transition(timer,timerIsUTC,trans_start,trans_end);
   GetLocalTimezone:=assigned(info);
   if not GetLocalTimezone then
    exit;
@@ -128,9 +130,9 @@ begin
 end;
 
 
-procedure GetLocalTimezone(timer:cint);
+procedure GetLocalTimezone(timer:cint;timerIsUTC:Boolean);
 begin
-  GetLocalTimezone(timer,Tzinfo,true);
+  GetLocalTimezone(timer,timerIsUTC,Tzinfo,true);
 end;
 
 Const
@@ -349,9 +351,8 @@ end;
 
 procedure InitLocalTime;
 begin
-  ReloadTzinfo:=@InitLocalTime;
   ReadTimezoneFile(GetTimezoneFile);
-  GetLocalTimezone(fptime);
+  GetLocalTimezone(fptime,false);
 end;
 
 

+ 165 - 5
rtl/unix/unix.pp

@@ -16,9 +16,8 @@ Unit Unix;
 Interface
 
 Uses
-  BaseUnix,UnixType,
-  UnixUtil  // tzseconds
-  ;
+  BaseUnix,UnixType;
+
 // If you deprecated new symbols, please annotate the version.
 // this makes it easier to decide if they can already be removed.
 
@@ -54,6 +53,22 @@ Const
 
 {** Time/Date Handling **}
 
+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
+  Tzinfo : TTZInfo;
+
+  Function GetTzseconds : Longint;
+  property Tzseconds : Longint read GetTzseconds;
   function Gettzdaylight : boolean;
   function Gettzname(const b : boolean) : pchar;
   property tzdaylight : boolean read Gettzdaylight;
@@ -69,13 +84,21 @@ Const
                        // it doesn't (yet) work for.
 
 { timezone support }
-function GetLocalTimezone(timer:cint;var ATZInfo:TTZInfo;FullInfo:Boolean):Boolean;
-procedure GetLocalTimezone(timer:cint);
+function GetLocalTimezone(timer:cint;timerIsUTC:Boolean;var ATZInfo:TTZInfo;FullInfo:Boolean):Boolean;
+procedure GetLocalTimezone(timer:cint;timerIsUTC:Boolean);
 procedure ReadTimezoneFile(fn:string);
 function  GetTimezoneFile:string;
 Procedure ReReadLocalTime;
 {$ENDIF}
 
+Procedure RefreshTZInfoIfNeeded;
+Function UniversalToEpoch(year,month,day,hour,minute,second:Word):int64; // use DateUtils.DateTimeToUnix for cross-platform applications
+Function LocalToEpoch(year,month,day,hour,minute,second:Word):int64; // use DateUtils.DateTimeToUnix for cross-platform applications
+Procedure EpochToLocal(epoch:int64;var year,month,day,hour,minute,second:Word); // use DateUtils.UnixToDateTime for cross-platform applications
+Procedure EpochToUniversal(epoch:int64;var year,month,day,hour,minute,second:Word); // use DateUtils.UnixToDateTime for cross-platform applications
+Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word); // use DateUtils.DateTimetoJulianDate for cross-platform applications
+Function GregorianToJulian(Year,Month,Day:Longint):LongInt; // use DateUtils.JulianDateToDateTime for cross-platform applications
+
 {**  Process Handling  **}
 
 function FpExecLE (Const PathName:RawByteString;const S:Array Of RawByteString;MyEnv:ppchar):cint;
@@ -164,6 +187,11 @@ Function getenv(name:string):Pchar; external name 'FPC_SYSC_FPGETENV';
                           timezone support
 ******************************************************************************}
 
+Function GetTzseconds : Longint;
+begin
+  GetTzseconds:=Tzinfo.seconds;
+end;
+
 function Gettzdaylight : boolean;
 begin
   Gettzdaylight:=Tzinfo.daylight;
@@ -174,6 +202,137 @@ begin
   Gettzname:=Tzinfo.name[b];
 end;
 
+Const
+{Date Translation}
+  C1970=2440588;
+  D0   =   1461;
+  D1   = 146097;
+  D2   =1721119;
+
+Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
+Var
+  YYear,XYear,Temp,TempMonth : LongInt;
+Begin
+  Temp:=((JulianDN-D2) shl 2)-1;
+  JulianDN:=Temp Div D1;
+  XYear:=(Temp Mod D1) or 3;
+  YYear:=(XYear Div D0);
+  Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
+  Day:=((Temp Mod 153)+5) Div 5;
+  TempMonth:=Temp Div 153;
+  If TempMonth>=10 Then
+   Begin
+     inc(YYear);
+     dec(TempMonth,12);
+   End;
+  inc(TempMonth,3);
+  Month := TempMonth;
+  Year:=YYear+(JulianDN*100);
+end;
+
+Procedure EpochToLocal(epoch:Int64;var year,month,day,hour,minute,second:Word);
+{
+  Transforms Epoch time into local time (hour, minute,seconds)
+}
+Var
+  DateNum: LongInt;
+  lTZInfo: TTZInfo;
+Begin
+  { check if time is in current global Tzinfo }
+  if (Tzinfo.validsince<epoch) and (epoch<Tzinfo.validuntil) then
+    inc(Epoch,TZInfo.seconds)
+  else
+  begin
+    {$if declared(GetLocalTimezone)}
+    if GetLocalTimezone(epoch,true,lTZInfo,false) then
+      inc(Epoch,lTZInfo.seconds)
+    else { fallback }
+    {$endif}
+      inc(Epoch,TZInfo.seconds);
+  end;
+
+  EpochToUniversal(epoch,year,month,day,hour,minute,second);
+End;
+
+Procedure EpochToUniversal(epoch:Int64;var year,month,day,hour,minute,second:Word);
+{
+  Transforms Epoch time into universal time (hour, minute,seconds)
+}
+Var
+  DateNum: LongInt;
+Begin
+  Datenum:=(Epoch Div 86400) + c1970;
+  JulianToGregorian(DateNum,Year,Month,day);
+  Epoch:=Abs(Epoch Mod 86400);
+  Hour:=Epoch Div 3600;
+  Epoch:=Epoch Mod 3600;
+  Minute:=Epoch Div 60;
+  Second:=Epoch Mod 60;
+End;
+
+Function LocalToEpoch(year,month,day,hour,minute,second:Word):Int64;
+{
+  Transforms local time (year,month,day,hour,minutes,second) to Epoch time
+   (seconds since 00:00, january 1 1970, corrected for local time zone)
+}
+Var
+  lTZInfo: TTZInfo;
+  UniversalEpoch: Int64;
+Begin
+  UniversalEpoch:=UniversalToEpoch(year,month,day,hour,minute,second);
+  { check if time is in current global Tzinfo }
+  if (Tzinfo.validsince<UniversalEpoch-Tzinfo.seconds) and (UniversalEpoch-Tzinfo.seconds<Tzinfo.validuntil) then
+    LocalToEpoch:=UniversalEpoch-TZInfo.seconds
+  else
+  begin
+    {$if declared(GetLocalTimezone)}
+    if GetLocalTimezone(LocalToEpoch,false,lTZInfo,false) then
+      LocalToEpoch:=UniversalEpoch-lTZInfo.seconds
+    else { fallback }
+    {$endif}
+      LocalToEpoch:=UniversalEpoch-TZInfo.seconds
+  end;
+End;
+
+Function UniversalToEpoch(year,month,day,hour,minute,second:Word):Int64;
+{
+  Transforms universal time (year,month,day,hour,minutes,second) to Epoch time
+   (seconds since 00:00, january 1 1970, corrected for local time zone)
+}
+Begin
+  UniversalToEpoch:=(Int64(GregorianToJulian(Year,Month,Day)-c1970)*86400)+
+                (LongInt(Hour)*3600)+(Longint(Minute)*60)+Second;
+End;
+
+Function GregorianToJulian(Year,Month,Day:Longint):LongInt;
+Var
+  Century,XYear: LongInt;
+Begin
+  If Month<=2 Then
+   Begin
+     Dec(Year);
+     Inc(Month,12);
+   End;
+  Dec(Month,3);
+  Century:=(longint(Year Div 100)*D1) shr 2;
+  XYear:=(longint(Year Mod 100)*D0) shr 2;
+  GregorianToJulian:=((((Month*153)+2) div 5)+Day)+D2+XYear+Century;
+End;
+
+Procedure RefreshTZInfoIfNeeded;
+{$if declared(ReReadLocalTime)}
+var
+  curtime: time_t;
+begin
+  curtime:=fptime;
+  if ((curtime<Tzinfo.validsince+Tzinfo.seconds) or (curtime>Tzinfo.validuntil+Tzinfo.seconds)) then
+    GetLocalTimezone(fptime,false);
+end;
+{$else}
+begin
+end;
+{$endif}
+
 {******************************************************************************
                           Process related calls
 ******************************************************************************}
@@ -446,6 +605,7 @@ end;
 {$IFNDEF DONT_READ_TIMEZONE}
 { Include timezone handling routines which use /usr/share/timezone info }
 {$i timezone.inc}
+
 {$endif}
 {******************************************************************************
                            FileSystem calls

+ 0 - 114
rtl/unix/unixutil.pp

@@ -29,45 +29,12 @@ 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
-  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;
 function ArrayStringToPPchar(const S:Array of RawByteString;reserveentries:Longint):ppchar; // const ?
-Function LocalToEpoch(year,month,day,hour,minute,second:Word):int64; deprecated 'use DateUtils.DateTimeToUnix';
-Procedure EpochToLocal(epoch:int64;var year,month,day,hour,minute,second:Word); deprecated 'use DateUtils.UnixToDateTime';
-Procedure EpochToUniversal(epoch:int64;var year,month,day,hour,minute,second:Word); deprecated 'use DateUtils.UnixToDateTime';
-Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word); deprecated 'use DateUtils.DateTimetoJulianDate';
-Function GregorianToJulian(Year,Month,Day:Longint):LongInt; deprecated 'use DateUtils.JulianDateToDateTime';
 
 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
@@ -174,85 +141,4 @@ begin
    end;
 end;
 
-Const
-{Date Translation}
-  C1970=2440588;
-  D0   =   1461;
-  D1   = 146097;
-  D2   =1721119;
-
-
-Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
-Var
-  YYear,XYear,Temp,TempMonth : LongInt;
-Begin
-  Temp:=((JulianDN-D2) shl 2)-1;
-  JulianDN:=Temp Div D1;
-  XYear:=(Temp Mod D1) or 3;
-  YYear:=(XYear Div D0);
-  Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
-  Day:=((Temp Mod 153)+5) Div 5;
-  TempMonth:=Temp Div 153;
-  If TempMonth>=10 Then
-   Begin
-     inc(YYear);
-     dec(TempMonth,12);
-   End;
-  inc(TempMonth,3);
-  Month := TempMonth;
-  Year:=YYear+(JulianDN*100);
-end;
-
-Procedure EpochToLocal(epoch:Int64;var year,month,day,hour,minute,second:Word);
-{
-  Transforms Epoch time into local time (hour, minute,seconds)
-}
-Var
-  DateNum: LongInt;
-Begin
-  inc(Epoch,TZSeconds);
-  EpochToUniversal(epoch,year,month,day,hour,minute,second);
-End;
-
-Procedure EpochToUniversal(epoch:Int64;var year,month,day,hour,minute,second:Word);
-{
-  Transforms Epoch time into universal time (hour, minute,seconds)
-}
-Var
-  DateNum: LongInt;
-Begin
-  Datenum:=(Epoch Div 86400) + c1970;
-  JulianToGregorian(DateNum,Year,Month,day);
-  Epoch:=Abs(Epoch Mod 86400);
-  Hour:=Epoch Div 3600;
-  Epoch:=Epoch Mod 3600;
-  Minute:=Epoch Div 60;
-  Second:=Epoch Mod 60;
-End;
-
-Function LocalToEpoch(year,month,day,hour,minute,second:Word):Int64;
-{
-  Transforms local time (year,month,day,hour,minutes,second) to Epoch time
-   (seconds since 00:00, january 1 1970, corrected for local time zone)
-}
-Begin
-  LocalToEpoch:=(Int64(GregorianToJulian(Year,Month,Day)-c1970)*86400)+
-                (LongInt(Hour)*3600)+(Longint(Minute)*60)+Second-TZSeconds;
-End;
-
-Function GregorianToJulian(Year,Month,Day:Longint):LongInt;
-Var
-  Century,XYear: LongInt;
-Begin
-  If Month<=2 Then
-   Begin
-     Dec(Year);
-     Inc(Month,12);
-   End;
-  Dec(Month,3);
-  Century:=(longint(Year Div 100)*D1) shr 2;
-  XYear:=(longint(Year Mod 100)*D0) shr 2;
-  GregorianToJulian:=((((Month*153)+2) div 5)+Day)+D2+XYear+Century;
-End;
-
 end.

+ 2 - 2
utils/fppkg/lnet/lcommon.pp

@@ -363,7 +363,7 @@ end;
 
 // unix
 
-  ,Errors, UnixUtil;
+  ,Errors, Unix;
 
 function LStrError(const Ernum: Longint; const UseUTF8: Boolean = False): string;
 begin
@@ -461,7 +461,7 @@ end;
 
 function TZSeconds: Integer; inline;
 begin
-  Result := unixutil.TZSeconds;
+  Result := unix.TZSeconds;
 end;
 
 {$ENDIF}