diff options
author | ondrej <ondrej@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2020-11-03 14:27:07 +0000 |
---|---|---|
committer | ondrej <ondrej@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2020-11-03 14:27:07 +0000 |
commit | c7db5a01f645fa12a9d233c87a29eb7b45812072 (patch) | |
tree | 104fab296c58662422514abd453bfb59d68c1092 /rtl | |
parent | 7d84c8f42080bed5dd7dfb0158465797f114501d (diff) | |
download | fpc-c7db5a01f645fa12a9d233c87a29eb7b45812072.tar.gz |
LocalToEpoch, EpochToLocal: fix for arbitrary datetime
git-svn-id: https://svn.freepascal.org/svn/fpc/trunk@47291 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'rtl')
-rw-r--r-- | rtl/unix/dos.pp | 86 | ||||
-rw-r--r-- | rtl/unix/sysutils.pp | 52 | ||||
-rw-r--r-- | rtl/unix/timezone.inc | 19 | ||||
-rw-r--r-- | rtl/unix/unix.pp | 170 | ||||
-rw-r--r-- | rtl/unix/unixutil.pp | 114 |
5 files changed, 177 insertions, 264 deletions
diff --git a/rtl/unix/dos.pp b/rtl/unix/dos.pp index 731ab8b9de..14e1271c2d 100644 --- a/rtl/unix/dos.pp +++ b/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; diff --git a/rtl/unix/sysutils.pp b/rtl/unix/sysutils.pp index 2d6e79531b..1803bf2d04 100644 --- a/rtl/unix/sysutils.pp +++ b/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; diff --git a/rtl/unix/timezone.inc b/rtl/unix/timezone.inc index b8bdbf4685..279b8cf2be 100644 --- a/rtl/unix/timezone.inc +++ b/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; diff --git a/rtl/unix/unix.pp b/rtl/unix/unix.pp index 00c741d0e1..6f21c3e4b1 100644 --- a/rtl/unix/unix.pp +++ b/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 diff --git a/rtl/unix/unixutil.pp b/rtl/unix/unixutil.pp index 88ad329823..fdebca5831 100644 --- a/rtl/unix/unixutil.pp +++ b/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. |