1

We are working on a data logging application in Beckhoff TwinCAT3. To get the time we are currently using LTIME(), then converting that in C# to ms using:

ulong valA = reader.ReadUInt64();   // this gets the LTIME
long ftime = (long)(valA / 100);
DateTime t = DateTime.FromFileTime(ftime);
return (t.ToUniversalTime().Ticks - 621355968000000000) / 10000;

There must be a better way. Also, we are seeing a difference between this time and the computer time (the one in the task bar).

What is the best way to get ms since 1970 (GMT) from the computer clock?

I see NT_GetTime. That looks like we would then need to do math on the struct

Thanks for any pointers.

kjlowe
  • 78
  • 1
  • 9
  • As an important note: Especially if the the timespan between your data points needs to be very accurate it matters how you resolve the time on the plc. NT_GetTime is jittering / not so accurate. See [Infosys](https://infosys.beckhoff.com/content/1031/tcplclib_tc2_utilities/18014398544903307.html) – Felix Keil Jan 23 '17 at 14:46

1 Answers1

3

The key to this is using FB_TzSpecificLocalTimeToFileTime to covert the current T_FILETIME to UTC using current timezone information (ST_TimeZoneInformation). This will you a UTC windows filetime (ticks) which needs to be coverted to UTC unix time.

Here is a function block implementation of this process:

Declaration

FUNCTION_BLOCK UnixTimestamp
VAR_OUTPUT
    seconds: ULINT;
    milliseconds: ULINT;
END_VAR

VAR
    localSystemTime : FB_LocalSystemTime := ( bEnable := TRUE, dwCycle := 1 );
    getTimeZoneInformation : FB_GetTimeZoneInformation;
    timeZoneInformation : ST_TimeZoneInformation;
    specificLocalTimeToFileTime : FB_TzSpecificLocalTimeToFileTime;
    fileTime: T_FILETIME;
    onZerothSecondLastCycle : BOOL;
END_VAR

Implementation

// Get local system time
localSystemTime();

// On the zeroth second of each minutesync timezone information
IF (timeZoneInformation.standardName = '' OR (localSystemTime.systemTime.wSecond = 0 AND NOT onZerothSecondLastCycle)) THEN
    getTimeZoneInformation(sNetID := '', bExecute := TRUE, tzInfo => timeZoneInformation);
END_IF;

// Convert local system time to unix timestamps
specificLocalTimeToFileTime(in := Tc2_Utilities.SYSTEMTIME_TO_FILETIME(localSystemTime.systemTime), tzInfo := timeZoneInformation, out => fileTime);
seconds := (SHL(DWORD_TO_ULINT(fileTime.dwHighDateTime), 32) + DWORD_TO_ULINT(fileTime.dwLowDateTime)) / 10000000 - 11644473600;
milliseconds := (SHL(DWORD_TO_ULINT(fileTime.dwHighDateTime), 32) + DWORD_TO_ULINT(fileTime.dwLowDateTime)) / 10000 - 11644473600000;

onZerothSecondLastCycle := localSystemTime.systemTime.wSecond = 0;

Usage

VAR
    unixTime: UnixTimestamp;
    timestampSeconds: ULINT;
    timestampMilliseconds: ULINT;
END_VAR

-----

unixTime();
timestampMilliseconds := unixTime.milliseconds;
timestampSeconds := unixTime.seconds;
kjlowe
  • 78
  • 1
  • 9