summaryrefslogtreecommitdiff
path: root/rtl
diff options
context:
space:
mode:
authorondrej <ondrej@3ad0048d-3df7-0310-abae-a5850022a9f2>2020-11-03 14:27:07 +0000
committerondrej <ondrej@3ad0048d-3df7-0310-abae-a5850022a9f2>2020-11-03 14:27:07 +0000
commitc7db5a01f645fa12a9d233c87a29eb7b45812072 (patch)
tree104fab296c58662422514abd453bfb59d68c1092 /rtl
parent7d84c8f42080bed5dd7dfb0158465797f114501d (diff)
downloadfpc-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.pp86
-rw-r--r--rtl/unix/sysutils.pp52
-rw-r--r--rtl/unix/timezone.inc19
-rw-r--r--rtl/unix/unix.pp170
-rw-r--r--rtl/unix/unixutil.pp114
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.