Time Variable Conversion

Some query functions, such as TIMERANGE, require the date and time to be entered in a specific format that does not have some key properties. Current restrictions to this are:

  • local time offset to UTC,
  • inability to specifically set daylight saving time(DST),
  • no standardised format.
Note: The inability to specify the offset to UTC presents a problem when changing the DST, especially when changing from daylight saving time to standard time. In this case when going back from 3AM to 2AM an individual solution must be implemented to distinguish the hour between 2AM and 3AM daylight saving time and standard time.
Note:

Note the following for the time values and variables:

  • Runtime values/alarms can be created with an accuracy of up to nanoseconds.
  • Historical databases retain the correct sequence, but only store up to milliseconds, i.e. they discard the parts with higher accuracy.
  • The comparison of WinCC OA time variables only takes milliseconds into account. WinCC OA time variables that only differ in the microsecond or nanosecond range would be considered the same by the built-in comparison methods.

Date-Time formats in WinCC OA

Currently, there are multiple ways to convert Date-Time from a human-readable string format to a time variable.

scanTimeUTC()

Determines the local time from a UTC time string:

  • UTC date-time string in the format YYYY.MM.DD HH:MM:SS.mmm
  • "ISO" format: YYYY-MM-DDTHH:MM:SS.mmm

httpParseDate()

Allows parsing an RFC-2616 conform date string, e.g. from header "If-Modified-Since".

  • Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
  • Sunday, 06-Nov-94 08:49:37 GMT; RFC 850, obsoleted by RFC 1036
  • Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
Note: The time zone parameter is ignored! All HTTP date/time stamps must be represented in Greenwich Mean Time (GMT), without exception. For the purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal Time).

Conversion of WinCC OA TextVar to TimeVar variables.

Documented format:

  • Local date-time string in the format YYYY.MM.DD HH:MM:SS.mmm

Additional possible formats:

  • Local date-time string in the format YY.MM.DD HH:MM:SS.mmm
  • Local time string in the format HH:MM:SS.mmm
  • Local date-time string in the format YYYY.MM.DD HH:MM:SS.mmm acount
  • If date is missing day parameter it is set to 1.

Additional rules:

  • if month > 12 then month = 12
  • if month < 1 then month = 1
  • if day > 31 then day = 31
  • if day < 1 then day = 1
Warning: Bad input formatting is not handled.

Examples of additional conversion rules:

Input[In local time zone] Output[In local time zone]
21:30:01.010 <current date> 21:30:01.010 e.g. 2023.02.17 21:30:01.010
21:30:01 <current date> 21:30:01.000 e.g. 2023.02.17 21:30:01.000
21:30 <current date> 21:30:00.000 e.g. 2023.02.17 21:30:00.000
21: <current date> 21:00:00.000 e.g. 2023.02.17 21:00:00.000
21 1970.1.1 21:00:00.000
2023.12.26 2023.12.26 00:00:00.000
2023.12 2023.12.01 00:<random-Memory Access Violation>:00.000
2023.12. 2023.12.01 00:00:00.000
2023. 2023.01.01 00:00:00.000
2023.12.01 21 2023.12.01 21:00:00.00
abcdef 1970.01.01 01:00:00.000
abc.def 2000.01.01 00:00:00.000
abc:def <current date> 01:00:00.000
abc def 1970.01.01 01:00:00.000
Date-Time overflow processing
2038.99.99 25:61:61 2038.12.31 23:59:59.000
2023.01.99 00:00:00 2023.01.31 00:00:00.000
2023.02.99 00:00:00 2023.03.03 00:00:00.000

Handling bad input format

scanTimeUTC()

There is an entry in the error section that says "For example: no/incorrect parameters, incorrect format", but when the wrong input is entered, the getLastError function does not return any error. The returned time will have the value 1970.01.01 00:00:00.000 UTC.

DateTime overflow:

  • Input in ISO format will result in 1970.01.01 00:00:00.000 UTC.
  • Input in non ISO format can correctly handle overflow in fields: DD HH:MM:SS.mmm

makeTime()

Uses system C mktime function which handles overflow correction correctly e.g. makeTime(2023,8,32,13,50) creates the time 2023.09.01 13:50:00.000.

Casting string variable to time variable.

Uses an automatic correction (clamping to max, min value) or will return 1970.01.01 01:00:00.000 value. No information is provided to the user.

ISO8601 Requirements

The user should be able to enter data in a human-readable time format according to ISO8601. At the same time, backward compatibility with legacy date and time formatting options should be maintained. Incorrect date and time format can be detected. These requirements apply to SQL queries (e.g., TIMERANGE) and to the conversion of WinCC OA TextVar to TimeVar variables.

Allowed formats

ISO8601 - with extended time format

  • Standard format: yyyy-MM-ddThh:mm:ss.sss[Z|[+|-]hh:mm]
  • Extended format for ExtTimeVar:
    yyyy-MM-ddThh:mm:ss.sss[Z|[+|-]hh:mm]
            aCount
    where:
     YYYY = four-digit year
     MM   = two-digit month (01=January, etc.)
     DD   = two-digit day of month (01 through 31)
     hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
     mm   = two digits of minute (00 through 59)
     ss   = two digits of second (00 through 59)
     s    = one or more digits representing a decimal fraction of a second
     TZD  = time zone designator (Z or +hh:mm or -hh:mm)
     aCount - alert count
    

Examples of valid inputs: Date and time in: 2023-02-15T06:48:32.500+00:00 UTC: 2023-02-15T06:48:32.500Z

Legacy date-time formats

  • UTC date-time string in the format "YYYY.MM.DD HH:MM:SS.mmm"
  • UTC date-time string in the format "YY.MM.DD HH:MM:SS.mmm"
  • UTC time string in the format "HH:MM:SS.mmm"
  • UTC date-time string in the format "YYYY.MM.DD HH:MM:SS.mmm aCount"

Expected behavior for legacy string conversion to TimeVar:

Input[In local time zone] Output[In local time zone] Valid Warning/Error
2023.12.01 21:30:01.001 2023.12.01 21:30:01.001 Yes No
2023.12.01 21:30:01.001<whitespace> 2023.12.01 21:30:01.001 Yes No
2023.12.01 21:30:01 2023.12.01 21:30:01.000 Yes No
2023.12.01 21:30 2023.12.01 21:30:00.000 Yes No
2023.12.01 21: 2023.12.01 21:00:00.000 No Error
2023.12.01 21 2023.12.01 21:00:00.00 No Error
2023.12 21:30:01.001 2023.12.01 21:30:01.001 No Error
2023.12 21:30:01.001 2023.12.01 21:30:01.001 No Error
2023. 21:30:01.001 2023.01.01 21:30:01.001 No Error
21:30:01.010 <current date> 21:30:01.010 e.g. 2023.02.17 21:30:01.010 No Warning
21:30:01 <current date> 21:30:01.000 e.g. 2023.02.17 21:30:01.000 No Warning
21:30 <current date> 21:30:00.000 e.g. 2023.02.17 21:30:00.000 No Warning
21: <current date> 21:00:00.000 e.g. 2023.02.17 21:00:00.000 No Error
21 1970.1.1 21:00:00.000 No Error
2023.12.26 2023.12.26 00:00:00.000 No Warning
2023.12 2023.12.01 00:00:00.000 No Error
2023.12. 2023.12.01 00:00:00.000 No Error
2023. 2023.01.01 00:00:00.000 No Error
abcdef 1970.01.01 01:00:00.000 No Error
abc.def 1970.01.01 01:00:00.000 No Error
abc:def 1970.01.01 01:00:00.000 No Error
abc def 1970.01.01 01:00:00.000 No Error
Date-Time overflow processing
2038.99.99 25:61:61 2038.12.31 23:59:59.000 No Error
2023.01.99 00:00:00 2023.01.31 00:00:00.000 No Error
2023.02.99 00:00:00 2023.02.28 00:00:00.000 No Error
Note: The handling of day overflow in a month involves verifying that the inputted day is within the specific limit for that month.

Expected behavior for legacy string conversion to ExtTimeVar:

Input[In local time zone] Output[In local time zone] Valid Warning/Error
2023.12.01 21:30:01.001 125 2023.12.01 21:30:01.001 count: 125 Yes No
2023.12.01 21:30:01.001 | 125 2023.12.01 21:30:01.001 count: 125 Yes No
2023.12.01 21:30:01.001 (125) 2023.12.01 21:30:01.001 count: 125 Yes No
2023.12.01 21:30:01.001|125 2023.12.01 21:30:01.001 count: 125 Yes No
2023.12.01 21:30:01.001(125) 2023.12.01 21:30:01.001 count: 125 Yes No
2023.12.01 21:30:01.001 blaa125blaa 2023.12.01 21:30:01.001 count: 125 Yes No
2023.12.01 21:30:01.001blaa125blaa 2023.12.01 21:30:01.001 count: 125 Yes No
2023.12.01 21:30:01 125 2023.12.01 21:30:01.000 count: 125 Yes No
2023.12.01 21:30:01 |125 2023.12.01 21:30:01.000 count: 125 Yes No
2023.12.01 21:30 125 2023.12.01 21:30:00.000 count: 125 Yes No
2023.12.01 21:30 |125 2023.12.01 21:30:00.000 count: 125 Yes No
2023.12.01 21: 125 2023.12.01 21:00:00.000 count: 125 No Error
2023.12.01 21 125 2023.12.01 21:00:00.00 count: 0 No Error
2023.12 21:30:01.001 125 2023.12.01 21:30:01.001 count: 125 No Error
2023.12 21:30:01.001 125 2023.12.01 21:30:01.001 count: 125 No Error
2023. 21:30:01.001 125 2023.01.01 21:30:01.001 count: 125 No Error
21:30:01.010 125 <current date> 21:30:01.010 count: 125 No Warning
21:30:01 125 <current date> 21:30:01.000 count: 125 No Warning
21:30 125 <current date> 21:30:00.000 count: 125 No Warning
21: 125 <current date> 21:00:00.000 count: 0 No Error
21 125 1970.1.1 21:00:00.000 count: 0 No Error
21:30:00 -125 2023.12.01 21:30:00.000 count: 125 No Error
21:30:00 ABCD 2023.12.01 21:30:00.000 count: 0 No Error

Handling bad input format

TIMERANGE: If a user enters the date and time in SQL queries in the wrong format, the query is evaluated as invalid, e.g. dpQuery returns -1, which indicates an error. The error can be retrieved by a subsequent call to getLastError().

In the case of converting a string variable to a time variable, handling the wrong input format will produce warning/error message. To catch these types of errors, you can use the function setThrowErrorAsException(). This function enables the current thread to throw an exception in case of an error that can be caught using a try/catch block. When an error occurs after calling setThrowErrorAsException(), it will be thrown as an exception, which can then be caught and handled appropriately.

setThrowErrorAsException();
time t;
try
{
  t = (time)"2022-99-99T01:03:00.567";
}catch
{
  dyn_errClass err = getLastException();
  DebugN(err);
}

Output:

  WCCOActrl2:[dyn_errClass 1 items
  WCCOActrl2:WCCOActrl    (2), 2023.03.03 13:40:00.166, CTRL, WARNING,    51, Parameter incorrect, TimeVar, operator=, ISO format >error. Must be: YYYY-MM-DDTHH:MM:SS.mmm
  WCCOActrl2:		Stacktrace:
  WCCOActrl2:		     1: void main() at tests\TestFile.ctl:61
  WCCOActrl2:]

Example of log messages:

WCCOActrl    (2), 2023.02.16 15:40:11.189, IMPL, WARNING,    50, TimeVar, operator=, DateTime format error. Must be: YYYY.MM.DD HH:MM[:SS.mmm]
WCCOActrl    (2), 2023.02.16 15:40:11.189, IMPL, WARNING,    50, TimeVar, operator=, ISO format error. Must be: YYYY-MM-DDTHH:MM:SS.mmm
WCCOActrl    (2), 2023.02.16 15:40:11.189, IMPL, WARNING,    50, TimeVar, operator=, aCount format error. Must be: YYYY.MM.DD HH:MM[:SS.mmm] aCount