// 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
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.