Time & Date Conversion to Unix Epoch

I’m having a senior moment :slight_smile:
I have a Win32 SystemTime structure with all the individual components of a time stamp (IE, “2010-01-26 @ 07:53:41.0898”) , what’s the easiest way to convert it into the # of seconds since the linux date epoch (1970-01-01 00:00:00) ?

Hi Paul

StringTheory has some methods for those things but assuming you don’t have that, just extract the date out of your time stamp convert to Clarion date then subtract date(1,1,1970) and multiply that by the number of seconds in a day
(ie. 24 * 60 * 60).

Then get the time and convert hours and minutes to seconds and add that on.

Usually people use equates for the various conversions as Mark does here:

A search for your question turned up to convert it to a FILETIME (number of 100-nanosecond intervals since January 1, 1601 UTC) then some simple math to offset to 1970 and divide for seconds. You will need to use Clarion’s 64 bit RTL include i64.inc

Int64 GetSystemTimeAsUnixTime()
{
   //Get the number of seconds since January 1, 1970 12:00am UTC
   //Code released into public domain; no attribution required.

   const Int64 UNIX_TIME_START = 0x019DB1DED53E8000; //January 1, 1970 (start of Unix epoch) in "ticks"
   const Int64 TICKS_PER_SECOND = 10000000; //a tick is 100ns

   FILETIME ft;
   GetSystemTimeAsFileTime(&ft); //returns ticks in UTC

   //Copy the low and high parts of FILETIME into a LARGE_INTEGER
   //This is so we can access the full 64-bits as an Int64 without causing an alignment fault
   LARGE_INTEGER li;
   li.LowPart  = ft.dwLowDateTime;
   li.HighPart = ft.dwHighDateTime;
 
   //Convert ticks since 1/1/1970 into seconds
   return (li.QuadPart - UNIX_TIME_START) / TICKS_PER_SECOND;
}

Seems like using Clarion functions would be easier, maybe

  Epoch=(Date(st.wMonth, st.wDay, st.wYear) |
       - Date(1,1,1970) ) *24*60*60  |
              + st.wHour * 60 * 60 |
              + st.wMinute * 60 |
              + st.wSecond

Converting FileTime to SystemTime and vice versa is the easy part, the hard part is that this is C6 and I don’t have a i64.inc :slight_smile:
But thanks to all your suggestions I will play more tomorrow.

You should be able to do it using a DECIMAL(21) or (19)

const Int64 UNIX_TIME_START = 0x019DB1DED53E8000; //January 1, 1970 (start of Unix epoch) in "ticks"

Using the Windows Calculator Hex of above = 116444736000000000 Decimal
Divide by 10,000,000 = 11644473600 so its a smaller number

Seconds1601_1970   DECIMAL(11,0,11644473600)
FT_Dec DECIMAL(21)
FT_Dec = ft.dwHighDateTime 
FT_Dec *= 2 ^ 32               ! 2^32=4,294,967,296
FT_Dec += ft.dwLowDateTime 
FT_Dec /= 10000000            ! / 10,000,000 from nano to seconds
FT_Dec -= Seconds1601_1970
map
  module('windows')
      OS_GetSystemTime(*NET_SYSTEMTIME lpSystemTime), pascal, raw, name('GetSystemTime'), dll(1)
  end
end

NET_SYSTEMTIME          group, type
wYear                       ushort
wMonth                      ushort
wDayOfWeek                  ushort
wDay                        ushort
wHour                       ushort
wMinute                     ushort
wSecond                     ushort
wMilliseconds               ushort
                        end

!------------------------------------------------------------------------------
! Returns a REAL containing the milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now
_NetAll.GetElapsedTimeUTC     PROCEDURE (Long pBaseDate=61730)   ! 61730 = 1 jan 1970
msPerDay            real(24 * 60 * 60 * 1000)    ! don't make this an equate, needs to force the calc below to be real.
msPerHour           equate     (60 * 60 * 1000)
msPerMinute         equate          (60 * 1000)
msPerSecond         equate               (1000)
today               long
ans                 Real
tim                 Group(NET_SYSTEMTIME).

  code
  OS_GetSystemTime(tim)   ! returned time is for UTC not local time
  today = date(tim.wMonth,tim.wDay,tim.wYear)
  ans = (( today - pBaseDate ) * msPerDay ) + (tim.wHour * msPerHour) + (tim.wMinute * msPerMinute) + (tim.wSecond * msPerSecond) + tim.wMilliseconds
  return ans
!------------------------------------------------------------------------------
! Extracts Clarion Date from a Unix date/time (which is stored as Seconds since Jan 1 1970)
_NetAll.UnixToClarionDate               Procedure(Long p_DateTime)
  code
  if p_DateTime >= 86400
    return (int(p_DateTime / 86400) + 61730) ! 61730 = Date(1,1,1970)
  else                                       ! 86400 = seconds in 1 day
    return 0
  end
!------------------------------------------------------------------------------
! Extracts Clarion Time from a Unix date/time (which is stored as Seconds since Jan 1 1970)
_NetAll.UnixToClarionTime               Procedure(Long p_DateTime)
  code
  if p_DateTime < 0
    return 0
  end
  return(1+(p_DateTime % 86400) * 100) ! 86400 = seconds in 1 day
!------------------------------------------------------------------------------
! Converts a Clarion Date & Time to a Unix date/time (which is stored as Seconds since Jan 1 1970)
_NetAll.ClarionToUnixDate          Procedure(Long p_Date, Long p_Time)
  code
  if p_Date > 61730                                   ! 61730 = date(1,1,1970)
    return(((p_Date-61730)*86400) + (p_Time / 100))   ! 86400 = seconds in 1 day
  else
    return((p_Time / 100))
  end
!------------------------------------------------------------------------------