Browse Source

+ timezone support

peter 26 years ago
parent
commit
ed5e78cc36
2 changed files with 311 additions and 74 deletions
  1. 50 74
      rtl/linux/linux.pp
  2. 261 0
      rtl/linux/timezone.inc

+ 50 - 74
rtl/linux/linux.pp

@@ -478,16 +478,24 @@ Function SysCall(callnr:longint;var regs:SysCallregs):longint;
      Time/Date Handling
 ***************************}
 
-Function  GetEpochTime:longint;
-Procedure GetTimeOfDay(var tv:timeval;var tz:timezone);
-Procedure SetTimeOfDay(Const tv:timeval;const tz:timezone);
-Function  GetTimeOfDay: longint;
+var
+  tzdaylight : boolean;
+  tzseconds  : longint;
+  tzname     : array[boolean] of pchar;
+
+{ timezone support }
+procedure GetLocalTimezone(timer:longint;var leap_correct,leap_hit:longint);
+procedure GetLocalTimezone(timer:longint);
+procedure ReadTimezoneFile(fn:string);
+function  GetTimezoneFile:string;
+
+Procedure GetTimeOfDay(var tv:timeval);
+Function  GetTimeOfDay:longint;
 Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
 Function  LocalToEpoch(year,month,day,hour,minute,second:Word):Longint;
 Procedure GetTime(Var Hour,Minute,Second:Word);
 Procedure GetDate(Var Year,Month,Day:Word);
-Procedure GetTime(Var Hour,Minute,Second:Integer);
-Procedure GetDate(Var Year,Month,Day:Integer);
+Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
 
 {**************************
      Process Handling
@@ -735,9 +743,6 @@ Implementation
 
 Uses Strings;
 
-var
-  LocalTZ:TimeZone;
-
 
 { Get the definitions of textrec and filerec }
 {$i textrec.inc}
@@ -1275,32 +1280,20 @@ end;
 
 
 
-Procedure GetTimeOfDay(var tv:timeval;var tz:timezone);
+Procedure GetTimeOfDay(var tv:timeval);
 {
- Get the time of day and timezone.
+  Get the number of seconds since 00:00, January 1 1970, GMT
+  the time NOT corrected any way
 }
 var
   regs : SysCallregs;
 begin
   regs.reg2:=longint(@tv);
-  regs.reg3:=longint(@tz);
+  regs.reg3:=0;
   SysCall(SysCall_nr_gettimeofday,regs);
   LinuxError:=Errno;
 end;
 
-Procedure SetTimeOfDay(Const tv:timeval;Const tz:timezone);
-{
- Get the time of day and timezone.
-}
-var
-  regs : SysCallregs;
-begin
-  regs.reg2:=longint(@tv);
-  regs.reg3:=longint(@tz);
-  SysCall(SysCall_nr_settimeofday,regs);
-  LinuxError:=Errno;
-end;
-
 
 Function GetTimeOfDay: longint;
 {
@@ -1308,47 +1301,25 @@ Function GetTimeOfDay: longint;
   the time NOT corrected any way
 }
 var
-  t  : timeval ;
-  tz : timezone ;
-begin
-  gettimeofday(t,tz);{Sets LinuxError also}
-  GetTimeOfDay:=t.sec;
-end;
-
-
-Function GetEpochTime:longint;
-{
-  Get the number of seconds since 00:00, January 1 1970, GMT
-  the time is corrected according to the time zone, but NOT
-  DST corrected.
-}
-var
-  t : timeval ;
-  tz : timezone ;
-begin
-  gettimeofday(t,tz);{Sets LinuxError also}
-  Getepochtime:=t.sec-tz.minuteswest*60;
-end;
-
-
-
-Procedure InitEpochToLocal;
-var
-  tv:TimeVal;
+  regs : SysCallregs;
+  tv   : timeval;
 begin
-  GetTimeOfDay(tv,LocalTZ);
+  regs.reg2:=longint(@tv);
+  regs.reg3:=0;
+  SysCall(SysCall_nr_gettimeofday,regs);
+  LinuxError:=Errno;
+  GetTimeOfDay:=tv.sec;
 end;
 
 
 Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
 {
-  Transforms Epoch time(seconds since 00:00, january 1 1970, corrected for
-  local time zone) into local time (hour, minute,seconds)
+  Transforms Epoch time into local time (hour, minute,seconds)
 }
 Var
   DateNum: LongInt;
-Begin { Beginning of Localtime }
-//  dec(Epoch,LocalTZ.minuteswest*60);
+Begin
+  inc(Epoch,TZSeconds);
   Datenum:=(Epoch Div 86400) + c1970;
   JulianToGregorian(DateNum,Year,Month,day);
   Epoch:=Epoch Mod 86400;
@@ -1366,14 +1337,13 @@ Function LocalToEpoch(year,month,day,hour,minute,second:Word):Longint;
 }
 Begin
   LocalToEpoch:=((GregorianToJulian(Year,Month,Day)-c1970)*86400)+
-               (LongInt(Hour)*3600)+(Minute*60)+Second+(LocalTZ.minuteswest*60);
+                (LongInt(Hour)*3600)+(Minute*60)+Second-TZSeconds;
 End;
 
 
 Procedure GetTime(Var Hour,Minute,Second:Word);
 {
-  Gets the current time, adjusted to local time, but not DST,
-  in hours, minutes and seconds.
+  Gets the current time, adjusted to local time
 }
 var
   year,day,month:Word;
@@ -1385,8 +1355,7 @@ End;
 
 Procedure GetDate(Var Year,Month,Day:Word);
 {
-  Gets the current date, adjusted to local time, but not DST,
-  in year,month,day.
+  Gets the current date, adjusted to local time
 }
 var
   hour,minute,second : Word;
@@ -1395,16 +1364,16 @@ Begin
 End;
 
 
-Procedure GetTime(Var Hour,Minute,Second:Integer);
-begin
- GetTime(Word(Hour),Word(Minute),Word(Second));
-end;
-
+Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
+{
+  Gets the current date, adjusted to local time
+}
+Begin
+  EpochToLocal(GetTimeOfDay,year,month,day,hour,minute,second);
+End;
 
-Procedure GetDate(Var Year,Month,Day:Integer);
-begin
-  GetDate(Word(Year),Word(Month),Word(Day));
-end;
+{ Include timezone handling routines which use /usr/share/timezone info }
+{$i timezone.inc}
 
 
 {******************************************************************************
@@ -3808,13 +3777,20 @@ end;
 {$ENDIF}
 
 
-Begin
-  InitEpochToLocal;
+Initialization
+  InitLocalTime;
+
+finalization
+  DoneLocalTime;
+
 End.
 
 {
   $Log$
-  Revision 1.53  1999-11-14 21:35:04  peter
+  Revision 1.54  1999-12-01 22:46:59  peter
+    + timezone support
+
+  Revision 1.53  1999/11/14 21:35:04  peter
     * removed warnings
 
   Revision 1.52  1999/11/14 11:11:15  michael

+ 261 - 0
rtl/linux/timezone.inc

@@ -0,0 +1,261 @@
+{
+  $Id$
+
+  Support for timezone info in /usr/share/timezone
+}
+
+type
+  plongint=^longint;
+  pbyte=^byte;
+
+  ttzhead=packed record
+    tzh_reserved : array[0..19] of byte;
+    tzh_ttisgmtcnt,
+    tzh_ttisstdcnt,
+    tzh_leapcnt,
+    tzh_timecnt,
+    tzh_typecnt,
+    tzh_charcnt  : longint;
+  end;
+
+  pttinfo=^tttinfo;
+  tttinfo=packed record
+    offset : longint;
+    isdst  : boolean;
+    idx    : byte;
+    isstd  : byte;
+    isgmt  : byte;
+  end;
+
+  pleap=^tleap;
+  tleap=record
+    transition : longint;
+    change     : longint;
+  end;
+
+var
+  num_transitions,
+  num_leaps,
+  num_types    : longint;
+
+  transitions  : plongint;
+  type_idxs    : pbyte;
+  types        : pttinfo;
+  zone_names   : pchar;
+  leaps        : pleap;
+
+function find_transition(timer:longint):pttinfo;
+var
+  i : longint;
+begin
+  if (num_transitions=0) or (timer<transitions[0]) then
+   begin
+     i:=0;
+     while (i<num_types) and (types[i].isdst) do
+      inc(i);
+     if (i=num_types) then
+      i:=0;
+   end
+  else
+   begin
+     for i:=1 to num_transitions do
+      if (timer<transitions[i]) then
+       break;
+     i:=type_idxs[i-1];
+   end;
+  find_transition:=@types[i];
+end;
+
+
+procedure GetLocalTimezone(timer:longint;var leap_correct,leap_hit:longint);
+var
+  info : pttinfo;
+  i    : longint;
+begin
+  info:=find_transition(timer);
+  TZDaylight:=info^.isdst;
+  TZSeconds:=info^.offset;
+  i:=0;
+  while (i<num_types) and (i<2) do
+   begin
+     tzname[types[i].isdst]:=@zone_names[types[i].idx];
+     inc(i);
+   end;
+  tzname[info^.isdst]:=@zone_names[info^.idx];
+  leap_correct:=0;
+  leap_hit:=0;
+  i:=num_leaps;
+  while (i>0) do
+   begin
+     if (timer>leaps[i].transition) then
+      break;
+     dec(i);
+   end;
+  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;
+     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);
+        dec(i);
+      end;
+   end;
+end;
+
+
+procedure GetLocalTimezone(timer:longint);
+var
+  lc,lh : longint;
+begin
+  GetLocalTimezone(timer,lc,lh);
+end;
+
+
+procedure ReadTimezoneFile(fn:string);
+
+  procedure decode(var l:longint);
+  var
+    k : longint;
+    p : pbyte;
+  begin
+    p:=pbyte(@l);
+    if (p[0] and (1 shl 7))<>0 then
+     k:=not 0
+    else
+     k:=0;
+    k:=(k shl 8) or p[0];
+    k:=(k shl 8) or p[1];
+    k:=(k shl 8) or p[2];
+    k:=(k shl 8) or p[3];
+    l:=k;
+  end;
+
+var
+  f      : longint;
+  tzdir  : string;
+  tzhead : ttzhead;
+  i      : longint;
+  chars  : longint;
+  buf    : pbyte;
+begin
+  if fn='' then
+   fn:='localtime';
+  if fn[1]<>'/' then
+   begin
+     tzdir:=getenv('TZDIR');
+     if tzdir='' then
+      tzdir:='/usr/share/zoneinfo';
+     if tzdir[length(tzdir)]<>'/' then
+      tzdir:=tzdir+'/';
+     fn:=tzdir+fn;
+   end;
+  f:=fdopen(fn,Open_RdOnly);
+  if f<0 then
+   exit;
+  i:=fdread(f,tzhead,sizeof(tzhead));
+  if i<>sizeof(tzhead) then
+   exit;
+  decode(tzhead.tzh_timecnt);
+  decode(tzhead.tzh_typecnt);
+  decode(tzhead.tzh_charcnt);
+  decode(tzhead.tzh_leapcnt);
+  decode(tzhead.tzh_ttisstdcnt);
+  decode(tzhead.tzh_ttisgmtcnt);
+
+  num_transitions:=tzhead.tzh_timecnt;
+  num_types:=tzhead.tzh_typecnt;
+  chars:=tzhead.tzh_charcnt;
+
+  reallocmem(transitions,num_transitions*sizeof(longint));
+  reallocmem(type_idxs,num_transitions);
+  reallocmem(types,num_types*sizeof(tttinfo));
+  reallocmem(zone_names,chars);
+  reallocmem(leaps,num_leaps*sizeof(tleap));
+
+  fdread(f,transitions^,num_transitions*4);
+  fdread(f,type_idxs^,num_transitions);
+
+  for i:=0 to num_transitions-1 do
+   decode(transitions[i]);
+
+  for i:=0 to num_types-1 do
+   begin
+     fdread(f,types[i].offset,4);
+     fdread(f,types[i].isdst,1);
+     fdread(f,types[i].idx,1);
+     decode(types[i].offset);
+     types[i].isstd:=0;
+     types[i].isgmt:=0;
+   end;
+
+  fdread(f,zone_names^,chars);
+
+  for i:=0 to num_leaps-1 do
+   begin
+     fdread(f,leaps[i].transition,4);
+     fdread(f,leaps[i].change,4);
+     decode(leaps[i].transition);
+     decode(leaps[i].change);
+   end;
+
+  getmem(buf,tzhead.tzh_ttisstdcnt);
+  fdread(f,buf^,tzhead.tzh_ttisstdcnt);
+  for i:=0 to tzhead.tzh_ttisstdcnt-1 do
+   types[i].isstd:=byte(buf[i]<>0);
+  freemem(buf);
+
+  getmem(buf,tzhead.tzh_ttisgmtcnt);
+  fdread(f,buf^,tzhead.tzh_ttisgmtcnt);
+  for i:=0 to tzhead.tzh_ttisgmtcnt-1 do
+   types[i].isgmt:=byte(buf[i]<>0);
+  freemem(buf);
+  fdclose(f);
+end;
+
+
+function GetTimezoneFile:string;
+var
+  f,len : longint;
+  s : string;
+begin
+  GetTimezoneFile:='';
+  f:=fdopen('/etc/timezone',Open_RdOnly);
+  if f=0 then
+   exit;
+  len:=fdread(f,s[1],high(s));
+  s[0]:=chr(len);
+  len:=pos(#10,s);
+  if len<>0 then
+   s[0]:=chr(len-1);
+  fdclose(f);
+  GetTimezoneFile:=s;
+end;
+
+
+procedure InitLocalTime;
+begin
+  ReadTimezoneFile(GetTimezoneFile);
+  GetLocalTimezone(GetTimeOfDay);
+end;
+
+
+procedure DoneLocalTime;
+begin
+  freemem(transitions);
+  freemem(type_idxs);
+  freemem(types);
+  freemem(zone_names);
+  freemem(leaps);
+end;
+
+{
+  $Log$
+  Revision 1.1  1999-12-01 22:46:59  peter
+    + timezone support
+
+}