⏲ 🐧 Linux Clock - JulTob/Ada GitHub Wiki

The Linux Clock

The Ada.Calendar package is the standard method of working with time in Ada programs. If you need to interface with C programs, you may need to use Linux's time features.

The Linux clock functions are either kernel calls or are a part of the standard C library, and they don't need to be linked in with the -lc option.

Basic time functions

The basic Linux time functions work with the number of seconds since January 1, 1970. This is referred to as the epoch in the Linux man pages. Because of the limits of a long integer value, the Linux clock will stop working properly around the year 2038.

The basic functions use a long_integer for the time:

type time_t is new long_integer;

procedure time ( time : in out time_t);
pragma import( C, time );

Returns the current time.

function difftime( time1, time2 : time_t ) return long_float;
pragma import( C, difftime );

Returns the number of seconds between two times (as a long_float).

Timeval Calls - Microsecond Accuracy

The timeval kernel calls return (or set) the current time with microsecond accuracy using a timeval record.

type timeval is record
  tv_sec  : time_t; -- number of seconds (since epoch)
  tv_usec : long_integer; -- number of microseconds
end record;

type timezone is record
  tz_minuteswest : integer; -- minutes west of Greenwich
  tz_dsttime     : integer  -- unsupported in Linux
end record;

procedure gettimeofday( result : out integer; tv : in out timeval, tz : in out timezone );
pragma import(C, gettimeofday );
pragma import_valued_procedure( gettimeofday );

Get the current time as the number of microseconds since January 1, 1970. Returns 0 for success. ftime() is an obsolete version of this function

procedure settimeofday( result : out integer; tv : in out timeval; tz : in out timezone );
pragma import( C, settimeofday );
pragma import_valued_procedure( settimeofday );

Set the current time as the number of microseconds since January 1, 1970. Returns 0 for success.

procedure tzset;
pragma import( C, tzset );

Create the TZ environment variable, if it doesn't exist, and sets it to the current timezone as specified in /etc/localtime or /usr/lib/zoneinfo/localtime. This is automatically invoked by the standard C library time functions whenever necessary.

procedure adjtimex( result : out integer; buf : inout timex );
pragma import( C, adjtimex );

Tunes the kernel's clock for specific time parameters

Functions using the tm record

Besides the number of seconds elapsed since 1970, Linux can also work with records containing the time broken down into common measurements. These functions use a tm record. These functions are all a part of the standard C library.

type tm is record
   sec   : integer; -- seconds on the clock (0-59)
   min   : integer; -- minutes on the clock (0-59)
   hour  : integer; -- hour on the clock (0-23)
   mBasic time functions

The basic Linux time functions work with the number of seconds since January 1, 1970. This is referred to as the epoch in the Linux man pages. Because of the limits of a long integer value, the Linux clock will stop working properly around the year 2038.

The basic functions use a long_integer for the time:

type time_t is new long_integer;

procedure time ( time : in out time_t);
pragma import( C, time );

Returns the current time.

function difftime( time1, time2 : time_t ) return long_float;
pragma import( C, difftime );

Returns the number of seconds between two times (as a long_float).

Timeval Calls - Microsecond Accuracy

The timeval kernel calls return (or set) the current time with microsecond accuracy using a timeval record.

type timeval is record
  tv_sec  : time_t; -- number of seconds (since epoch)
  tv_usec : long_integer; -- number of microseconds
end record;

type timezone is record
  tz_minuteswest : integer; -- minutes west of Greenwich
  tz_dsttime     : integer  -- unsupported in Linux
end record;

procedure gettimeofday( result : out integer; tv : in out timeval, tz : in out timezone );
pragma import(C, gettimeofday );
pragma import_valued_procedure( gettimeofday );

Get the current time as the number of microseconds since January 1, 1970. Returns 0 for success. ftime() is an obsolete version of this function

procedure settimeofday( result : out integer; tv : in out timeval; tz : in out timezone );
pragma import( C, settimeofday );
pragma import_valued_procedure( settimeofday );

Set the current time as the number of microseconds since January 1, 1970. Returns 0 for success.

procedure tzset;
pragma import( C, tzset );

Create the TZ environment variable, if it doesn't exist, and sets it to the current timezone as specified in /etc/localtime or /usr/lib/zoneinfo/localtime. This is automatically invoked by the standard C library time functions whenever necessary.

procedure adjtimex( result : out integer; buf : inout timex );
pragma import( C, adjtimex );

Tunes the kernel's clock for specific time parameters

Functions using the tm record

Besides the number of seconds elapsed since 1970, Linux can also work with records containing the time broken down into common measurements. These functions use a tm record. These functions are all a part of the standard C library.

type tm is record
   sec   : integer; -- seconds on the clock (0-59)
   min   : integer; -- minutes on the clock (0-59)
   hour  : integer; -- hour on the clock (0-23)
   mday  : integer; -- day of the month (1-31)
   mon   : integer; -- month (0-11)
   year  : integer; -- year
   wday  : integer; -- day of the week (0-6)
   yday  : integer; -- day of the year (0-365)
   isdst : integer; -- >0 is daylight savings time, 0=not, <0 unknown
end record;

You will also need the Address_To_Access_Conversions package to convert C pointers to tm record into Ada access type pointers.

package TmPtrs is
  new System.Address_To_Access_Conversions( tm );

function localtime( time : in out time_t ) return system.address;
pragma import( C, localtime );

Change the time into a tm record, making changes for the current time zone. time is the C pointer to the seconds since 1970.

function gmtime( time : in out time_t ) return system.address;
pragma import( C, gmtime );

Change the time into a tm record for UTC (Coordinated Universal Time). time is the C pointer to the seconds since 1970.

function mktime( tm : system.address ) return time_t;
pragma import( C, mktime );

Convert a tm record into the seconds since 1970.

To get the current time in tm format,

  seconds_since_1970 : long_integer;
  tm_rec : tm;
  ...
  time( seconds_since_1970 );
  tm = TmPtrs.To_Pointer( localtime( seconds_since_1970'address ) ).all;

Time as a String

function asctime( tm : system.address ) return string;
pragma import( C, asctime );

Convert the tm into a standard UNIX time C string, such as you see with the ls -l shell command.

function ctime( time : in out time_t) return long_integer;
pragma import( C, ctime );

Get the current time as a standard UNIX time C string. It's equivalent to using asctime() on the localtime() of the current time().

procedure strftime( result: size_t; datestr : in out stringtype; max : size_t; format : string; tm : in out tmrec );
pragma import( C, strftime );

Like asctime(), converts a tm time into text. strftime() uses formatting codes to determine the appearance of the text, similar to the shell date command. Returns the length of the date string (including the ending ASCII.NUL). See the man page for complete details.

Example:

datestring : string(1..80);
...
statftime( datestringsize, datestring, datestring'size/8, "%I:%M" & ASCII.NUL, tm );
Ada.Text_IO.Put_Line( "The time is " & datestring( 1..datestringsize-1 ) );

Timer Functions

Timer functions use the timeval structure

function timerclear( tv : timeval );
function timerisset( tv : timeval );
function timercmp( t0, t1 : timeval; operator : ? );

 day  : integer; -- day of the month (1-31)
   mon   : integer; -- month (0-11)
   year  : integer; -- year
   wday  : integer; -- day of the week (0-6)
   yday  : integer; -- day of the year (0-365)
   isdst : integer; -- >0 is daylight savings time, 0=not, <0 unknown
end record;

You will also need the Address_To_Access_Conversions package to convert C pointers to tm record into Ada access type pointers.

package TmPtrs is
  new System.Address_To_Access_Conversions( tm );

function localtime( time : in out time_t ) return system.address;
pragma import( C, localtime );

Change the time into a tm record, making changes for the current time zone. time is the C pointer to the seconds since 1970.

function gmtime( time : in out time_t ) return system.address;
pragma import( C, gmtime );

Change the time into a tm record for UTC (Coordinated Universal Time). time is the C pointer to the seconds since 1970.

function mktime( tm : system.address ) return time_t;
pragma import( C, mktime );

Convert a tm record into the seconds since 1970.

To get the current time in tm format,

  seconds_since_1970 : long_integer;
  tm_rec : tm;
  ...
  time( seconds_since_1970 );
  tm = TmPtrs.To_Pointer( localtime( seconds_since_1970'address ) ).all;

Time as a String

function asctime( tm : system.address ) return string;
pragma import( C, asctime );

Convert the tm into a standard UNIX time C string, such as you see with the ls -l shell command.

function ctime( time : in out time_t) return long_integer;
pragma import( C, ctime );

Get the current time as a standard UNIX time C string. It's equivalent to using asctime() on the localtime() of the current time().

procedure strftime( result: size_t; datestr : in out stringtype; max : size_t; format : string; tm : in out tmrec );
pragma import( C, strftime );

Like asctime(), converts a tm time into text. strftime() uses formatting codes to determine the appearance of the text, similar to the shell date command. Returns the length of the date string (including the ending ASCII.NUL). See the man page for complete details.

Example:

datestring : string(1..80);
...
statftime( datestringsize, datestring, datestring'size/8, "%I:%M" & ASCII.NUL, tm );
Ada.Text_IO.Put_Line( "The time is " & datestring( 1..datestringsize-1 ) );

Timer Functions

Timer functions use the timeval structure

function timerclear( tv : timeval );
function timerisset( tv : timeval );
function timercmp( t0, t1 : timeval; operator : ? );