Lazarus

Free Pascal => Beginners => Topic started by: DevilDevil on April 01, 2020, 12:02:54 am

Title: Use UNIX function (localtime)
Post by: DevilDevil on April 01, 2020, 12:02:54 am
Unfortunately, I do not understand how to use the standard UNIX function localtime (https://linux.die.net/man/3/localtime)

Code: Pascal  [Select][+][-]
  1. function localtime(var time: time_t): PTm; cdecl;
Title: Re: Use UNIX function (localtime)
Post by: winni on April 01, 2020, 12:26:23 am
Hi!

Do you need the local time or do you want to dive in the Unix jungle?

The first is easy:

Code: Pascal  [Select][+][-]
  1. function Now : TDateTime;

gives you the local time.

Code: Pascal  [Select][+][-]
  1. function NowUTC: TDateTime;

gives you the international universal time.

The first is in unit sysutils, the later in LazSysutils.

To get your local timeoffset there is

Code: Pascal  [Select][+][-]
  1. GetLocalTimeOffset

which returns the Timezone in minutes.


Or do you prefer to fool around with imported C functions?
It is already there - as you can see.

Winni
Title: Re: Use UNIX function (localtime)
Post by: DevilDevil on April 02, 2020, 03:34:58 pm
winni,

Hi!

I need to call exactly UNIX (POSIX) functions. For example, in Delphi, this function is contained in the Posix.Time unit.
Title: Re: Use UNIX function (localtime)
Post by: marcov on April 02, 2020, 04:35:40 pm
I need to call exactly UNIX (POSIX) functions. For example, in Delphi, this function is contained in the Posix.Time unit.

Then declare the relevant functions and use them.  Delphi Linux units are not supported, since Delphi Linux support is still quite new (and FPC's dates from 1995)
Title: Re: Use UNIX function (localtime)
Post by: DevilDevil on April 03, 2020, 01:34:47 pm
Thanks

I am developing a low-level unit, I can not use SysUtils in it. Yes, I need to know the difference in seconds between local time and UTC. Similarly, I did this using the localtime function. But now, for some reason, time returns local time, not UTC. Does anyone know how to fix this?

Code: Pascal  [Select][+][-]
  1. {$if Defined(FPC) and Defined(UNIX)}
  2. const
  3.   libc = 'libc.so';
  4.  
  5. type
  6.   tm = packed record
  7.     tm_sec: Integer;            // Seconds. [0-60] (1 leap second)
  8.     tm_min: Integer;            // Minutes. [0-59]
  9.     tm_hour: Integer;           // Hours.[0-23]
  10.     tm_mday: Integer;           // Day.[1-31]
  11.     tm_mon: Integer;            // Month.[0-11]
  12.     tm_year: Integer;           // Year since 1900
  13.     tm_wday: Integer;           // Day of week [0-6] (Sunday = 0)
  14.     tm_yday: Integer;           // Days of year [0-365]
  15.     tm_isdst: Integer;          // Daylight Savings flag [-1/0/1]
  16.     tm_gmtoff: Integer;         // Seconds east of UTC
  17.     tm_zone: PAnsiChar;         // Timezone abbreviation
  18.   end;
  19.   Ptm = ^tm;
  20.  
  21. function time(var Timer: time_t): time_t; cdecl; external libc name 'time';
  22. function gmtime(var Timer: time_t): Ptm; cdecl; external libc name 'gmtime';
  23. function localtime(var Timer: time_t): Ptm; cdecl; external libc name 'localtime';
  24. {$ifend}
  25.  
  26. class function TOSTime.UpdateLocalDelta: Int64;
  27. {$ifdef MSWINDOWS}
  28. var
  29.   LUTCTime: TFileTime;
  30.   LLocalTime: TFileTime;
  31. begin
  32.   GetSystemTimeAsFileTime(LUTCTime);
  33.   FileTimeToLocalFileTime(LUTCTime, LLocalTime);
  34.   Result := Int64(LLocalTime) - Int64(LUTCTime);
  35.   TIMESTAMP_LOCAL_DELTA := Result;
  36. end;
  37. {$else .POSIX}
  38. var
  39.   LUtcTime: {$ifdef FPC}time_t{$else .DELPHI}Posix.SysTypes.time_t{$endif};
  40.   LTime, LLocalTime: {$ifdef FPC}Ptm{$else .DELPHI}Posix.Time.Ptm{$endif};
  41. begin
  42.   {$ifdef FPC}
  43.   time(LUtcTime);
  44.   LTime := gmtime(LUtcTime);
  45.   LLocalTime := localtime(LUtcTime); // LTime^ = LLocalTime^ !!!
  46.   {$else .DELPHI}
  47.   Posix.Time.time(@LUtcTime);
  48.   LTime := gmtime(LUtcTime);
  49.   LLocalTime := Posix.Time.localtime(LUtcTime);
  50.   {$endif}
  51.  
  52.   if (Assigned(LTime)) and (Assigned(LLocalTime)) then
  53.   begin
  54.     Result := LLocalTime.tm_gmtoff * TIMESTAMP_SECOND;
  55.   end else
  56.   begin
  57.     Result := 0;
  58.   end;
  59.  
  60.   TIMESTAMP_LOCAL_DELTA := Result;
  61. end;
  62. {$endif}  
     
Title: Re: Use UNIX function (localtime)
Post by: marcov on April 03, 2020, 01:49:11 pm
Did you test unixutils.tzseconds ? Though this is formally not supported (it is an Unix rtl internal unit)

Afaik time gives system clock, and it is a per system config if that is UTC or local.
Title: Re: Use UNIX function (localtime)
Post by: DevilDevil on April 03, 2020, 01:57:07 pm
marcov,

Yep. But this variable is initialized inside SysUtils. If the unit is not used, the variable is 0.
Title: Re: Use UNIX function (localtime)
Post by: marcov on April 03, 2020, 02:10:31 pm
marcov,

Yep. But this variable is initialized inside SysUtils. If the unit is not used, the variable is 0.

But is it correct if you do use sysutils just to test ? Then you can copy the way it is calculated (environment variable TZ iirc)
Title: Re: Use UNIX function (localtime)
Post by: Thaddy on April 03, 2020, 02:35:31 pm
There is support for the - Kylix compatibility - localtime in libc which is disabled by default. It has all the right declarations. See time.pas and timeh.inc.
(I would not call Kylix relatively recent...)
Title: Re: Use UNIX function (localtime)
Post by: DevilDevil on April 03, 2020, 06:28:51 pm
marcov

tzseconds is initialized in the GetLocalTimezone function of the timezone.inc file. Maybe it would be possible to copy the implementation, but the memory manager is used there, which I need to avoid (my unit, for example, can be used inside an alternative manager, so these functions cannot be used). I want to find a simple alternative way.

As far as I understand, the problem is that the time function returns local time, not UTC.
Title: Re: Use UNIX function (localtime)
Post by: DevilDevil on April 03, 2020, 06:34:52 pm
Thaddy,

The timeh.inc file is used inside the libc.pp unit, not time.pas. I don’t understand yet how to connect the libc.pp unit)
Title: Re: Use UNIX function (localtime)
Post by: marcov on April 03, 2020, 06:56:34 pm
Thaddy,

The timeh.inc file is used inside the libc.pp unit, not time.pas. I don’t understand yet how to connect the libc.pp unit)

The libc unit are just old (2005) header translations, and 32-bit x86 only. If you persist in this better roll your own.
Title: Re: Use UNIX function (localtime)
Post by: DevilDevil on April 03, 2020, 10:29:16 pm
Maybe after all someone knows how to make the time function return UTC?
Title: Re: Use UNIX function (localtime)
Post by: marcov on April 03, 2020, 10:39:08 pm
Maybe after all someone knows how to make the time function return UTC?

Configure your Linux to set your hardware clock to UTC?  Usually that is a question during installation.

Title: Re: Use UNIX function (localtime)
Post by: winni on April 03, 2020, 11:11:09 pm
Hi!

Then have a look inside of nowUTC:


Code: Pascal  [Select][+][-]
  1. function NowUTC: TDateTime;
  2. var
  3.   tz:timeval;
  4.   SystemTime: TSystemTime;
  5. begin
  6.   fpgettimeofday(@tz,nil);
  7.   EpochToLocal(tz.tv_sec,SystemTime.year,SystemTime.month,SystemTime.day,  
  8.    SystemTime.hour,SystemTime.Minute,SystemTime.Second);
  9.   SystemTime.MilliSecond:=tz.tv_usec div 1000;
  10.   result := systemTimeToDateTime(SystemTime);
  11. end;        
  12.  

As you dont want to use Sysutils and LazSysutils let us discuss the single steps:

* fpgettimeofday is a built in fpc procedure
* EpochToLocal  is not so big and tricky - you can copy it from LazSysutils
* EpochToLocal uses JulianToGregorian which is only 20 lines with the old formula from Gauß.
*systemTimeToDateTime: you will not use it because it collects all values to build a TDateTime=Double. The values exist all in the record TSystemTime (hour, minute, ......)

So with let's say 2 screens you get the UTCtime.

Winni
Title: Re: Use UNIX function (localtime)
Post by: DevilDevil on April 07, 2020, 09:48:35 am
I found a way to get UTC time and calculate local! Thanks to all :)

Code: Pascal  [Select][+][-]
  1. {$if Defined(FPC) and Defined(UNIX)}
  2. const
  3.   libc = 'libc.so';
  4.  
  5. type
  6.   tm = packed record
  7.     tm_sec: Integer;            // Seconds. [0-60] (1 leap second)
  8.     tm_min: Integer;            // Minutes. [0-59]
  9.     tm_hour: Integer;           // Hours.[0-23]
  10.     tm_mday: Integer;           // Day.[1-31]
  11.     tm_mon: Integer;            // Month.[0-11]
  12.     tm_year: Integer;           // Year since 1900
  13.     tm_wday: Integer;           // Day of week [0-6] (Sunday = 0)
  14.     tm_yday: Integer;           // Days of year [0-365]
  15.     tm_isdst: Integer;          // Daylight Savings flag [-1/0/1]
  16.     tm_gmtoff: Integer;         // Seconds east of UTC
  17.     tm_zone: PAnsiChar;         // Timezone abbreviation
  18.   end;
  19.   Ptm = ^tm;
  20.  
  21. function localtime(var Timer: time_t): Ptm; cdecl; external libc name 'localtime';
  22. {$ifend}
  23.  
  24. class function TOSTime.UpdateLocalDelta: Int64;
  25. {$ifdef MSWINDOWS}
  26. var
  27.   LUTCTime: TFileTime;
  28.   LLocalTime: TFileTime;
  29. begin
  30.   GetSystemTimeAsFileTime(LUTCTime);
  31.   FileTimeToLocalFileTime(LUTCTime, LLocalTime);
  32.   Result := Int64(LLocalTime) - Int64(LUTCTime);
  33.   TIMESTAMP_LOCAL_DELTA := Result;
  34. end;
  35. {$else .POSIX}
  36. var
  37.   Ltm: Ptm;
  38.   LUtcTime: timespec;
  39.   LLocalTime: time_t;
  40. begin
  41.   clock_gettime(CLOCK_REALTIME_COARSE, @LUtcTime);
  42.   Ltm := localtime(LUtcTime.tv_sec);
  43.   LLocalTime := Ltm.tm_sec + Ltm.tm_min * 60 + Ltm.tm_hour * 3600 + Ltm.tm_yday * 86400 +
  44.     (Ltm.tm_year - 70) * 31536000 + ((Ltm.tm_year - 69) div 4) * 86400 -
  45.     ((Ltm.tm_year - 1) div 100) * 86400 + ((Ltm.tm_year + 299) div 400) * 86400;
  46.  
  47.   Result := (LLocalTime - LUtcTime.tv_sec) * TIMESTAMP_SECOND;
  48.   TIMESTAMP_LOCAL_DELTA := Result;
  49.   TIMESTAMP_REALTIMESTAMP_LOCAL_DELTA := TIMESTAMP_REALTIME_DELTA + Result;
  50. end;
  51. {$endif}
TinyPortal © 2005-2018