Tricky time handling software

Discussion about recent product features & solutions!
5 posts • Page 1 of 1
RudiKreiner
Posts:198
Joined: Mon May 16, 2011 2:10 pm

Tricky time handling software

Post by RudiKreiner »

I wrote a control script function that takes a timestamp from an S7 319F PLC (where time is defined in two unsigned integer datapoints, one containing the number of days since 1.1.1990 and another one containing the number of milliseconds since the beginning of the day) and converts that time to WinCC "time" format like this:

// convert 'nrDays' and 'nrMillis' as read from an S7 PLC to WinCC UTC time format
time ILM_calculateTime(unsigned nrDays, unsigned nrMillis)
{
time actualTime, t1970, t1990;
unsigned secs;
unsigned millis;
unsigned diffSecs;

// Linux starts counting secs since 1.1.1970
t1970 = makeTime(1970, 1, 1, 0, 0, 0, FALSE);
// S7 starts counting days and milli secs since 1.1.1990
t1990 = makeTime(1990, 1, 1, 0, 0, 0, FALSE);
diffSecs = t1990 - t1970; // Number of seconds between 1.1.1970 and 1.1.1990

secs = diffSecs + nrDays * 24 * 60 * 60 + nrMillis / MSEC_PER_SEC;
millis = nrMillis % MSEC_PER_SEC;

setPeriod(actualTime, secs, millis);
}


The script worked great in Germany and China, but returned an actual time that was off by 1 hour when I ran it on a Linux computer configured with the time of mainland Portugal, ie Lissabon. :ohmy:

It took me a while but I finally got to the root of the problem, which was that the portuguese government decided to switch from central European time to western European time in 1986.
I found that information here: https://en.wikipedia.org/wiki/Time_in_Portugal which caused my value of diffSecs to be off by 3600 seconds.

Changing the function like this solved the problem:

// convert 'nrDays' and 'nrMillis' as read from an S7 PLC to WinCC UTC time format
time ILM_calculateTime(unsigned nrDays, unsigned nrMillis) {

unsigned secs;
unsigned millis;
unsigned diffSecs;

// Linux starts counting secs since 1.1.1970
// but S7 starts counting days and milli secs since 1.1.1990
// so calculate offset in seconds for 20 years plus 5 days for the leap years
// in 1972, 1976, 1980, 1984 and 1988
diffSecs = (20 * 365+ 5) * 24* 3600;

secs = diffSecs + nrDays * 24* 3600+ nrMillis / 1000;
millis = nrMillis % 1000;

setPeriod(actualTime, secs, millis);
}


The purist in me wanted to get to the root of the problem and I found it in this statement.
t1970 = makeTime(1970, 1, 1, 0, 0, 0, FALSE);
The linux computer time zone is set to /usr/share/zoneinfo/Portugal and that file obviously contains the information about the time zone change in 1976.
Though not explicitly mentioned in the WinCC help page for makeTime(), this function interprets its input arguments in local time, not UTC.
Therefore the UTC time for t1970 was one hour off, because then local time was CET then, while the UTC time for t1990 was local time was WET then (which is the same as GMT)

While most of the readers of this post will just smile :) and maybe sympathise a bit with the exotic problems of a fellow programmer
I would propose to ETM to add a note to the help page that the makeTime() function interprets its input arguments in local time,
which may save someone some extra work in the future.

kilianvp
Posts:443
Joined: Fri Jan 16, 2015 10:29 am

Re: Tricky time handling software

Post by kilianvp »

You can use formatTimeUTC()

Code: Select all

main()
{
  time t1;
 
  string localTime;
  string utcTime;
 
  setTime(t1,2010,6,1,15);
 
  localTime = formatTime("%W; %c", t1, " ms: %04d");
  utcTime = formatTimeUTC("%W; %c", t1, " ms: %04d");
 
  DebugN("Local: ", localTime);
//Liefert: ["Local: "]["22; 01.06.2010 15:00:00 ms: 0000"]
  DebugN("UTC: ", utcTime);
//Liefert: ["UTC: "]["22; 01.06.2010 13:00:00 ms: 0000"]
}

mkoller
Posts:741
Joined: Fri Sep 17, 2010 9:03 am

Re: Tricky time handling software

Post by mkoller »

Interestingly the 3.15 German Help says it:
Beachten Sie das die übergebene, aufgespaltete Zeit eine Lokalzeit darstellt (nicht UTC). Das Ergebnis, also die time/atime Variable enthält aber danach die UTC Zeit - Sekunden seit 1.1.1970.

I'll make sure it will find it's way into the other languages as well ...

Side note: There's no need to use makeTime() to get the Unix 0-time at all, since a time variable is initialized as 0 time.

Gertjan van Schijndel
Posts:634
Joined: Mon Aug 02, 2010 10:37 am

Re: Tricky time handling software

Post by Gertjan van Schijndel »

Rudi Kreiner wrote:
I wrote a control script function that takes a timestamp from an S7 319F PLC (where time is defined in two unsigned integer datapoints, one containing the number of days since 1.1.1990 and another one containing the number of milliseconds since the beginning of the day) and converts that time to WinCC "time" format
Why not read the timestamp as a 'dateTime' value from the PLC?

RudiKreiner
Posts:198
Joined: Mon May 16, 2011 2:10 pm

Re: Tricky time handling software

Post by RudiKreiner »

Thanks for your comments.

For some reasons that are no longer valid, the date and time were passed from the PLC to a control script via a direct socket connection instead of the S7 driver.
If we had used the driver, I assume that its mapping routine would have handled the conversion automatically and saved me all this hassle.

Maybe I'll get around to refactoring that code . . .

5 posts • Page 1 of 1