Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Time and Date

Four things can be measured: how long something takes, which day it is, which moment of a day it is, and which exact point in time it is. The language has a type for each, in two families.

The short family is 32 bits wide, the long family is 64 bits and starts with L:

ShortLongHoldsWhat the short type counts
TIMELTIMEA durationmilliseconds
DATELDATEA dayseconds since 1970-01-01 UTC
TIME_OF_DAYLTIME_OF_DAYA moment of a daymilliseconds since midnight
DATE_AND_TIMELDATE_AND_TIMEA point in timeseconds since 1970-01-01 UTC

Each long type counts the same thing as the short type next to it, but in nanoseconds. Each type also has a short name: T, LT, D, LD, TOD, LTOD, DT, LDT.

A part of a value that is finer than what the type counts is lost. T#500us is a TIME of zero, and DT#1999-12-31-23:59:59.999 is the same DATE_AND_TIME as DT#1999-12-31-23:59:59. The long types count in nanoseconds and keep both.

The short types are unsigned. DATE and DATE_AND_TIME reach from 1970-01-01 to 2106-02-07, and TIME reaches T#49d17h2m47s295ms, about 49 days. A literal outside that range compiles with a warning and wraps around, so D#1969-12-31 is a day in February 2106 and T#49d17h2m47s296ms is zero. The long types are signed and reach about 292 years to either side of 1970, from LD#1677-09-22 to LD#2262-04-11. A long literal outside that range is rejected.

Literals

A literal starts with the name of its type and #:

VAR
    cycle: TIME := T#10ms;
    startup: TIME := TIME#2d4h6m8s10ms;
    day: DATE := D#2024-05-02;
    moment: TIME_OF_DAY := TOD#23:59:59.999;
    stamp: DATE_AND_TIME := DT#1999-12-31-23:59:59.999;
END_VAR

A duration is a sequence of segments, in the order d, h, m, s, ms, us, ns. You leave out the ones you do not need, and a segment can have a fraction:

T#2d4h          (* two days and four hours *)
T#2d4.2h        (* a segment may be fractional *)
T#90s           (* a segment may exceed its usual range *)

The order is not optional. A literal that changes it, such as T#4h2d, is rejected.

In a moment of a day or a point in time, only the seconds can have a fraction. A date has no fraction at all.

Calculating

Durations add and subtract, and they compare:

VAR
    a: TIME := T#1s;
    b: TIME := T#500ms;
    total: TIME;
END_VAR

total := a + b;        (* 1500 ms *)
IF a > b THEN          (* TRUE *)

A duration also multiplies and divides by a number, which is how you scale a cycle time: cycle * 2, 2 * cycle, cycle / 4, and cycle * 1.5 are all a TIME.

A duration shifts a moment of a day or a point in time, and two of those subtract to a duration. These are the combinations, within one family:

LeftOperatorRightResult
TIME+, -TIMETIME
TIME_OF_DAY+, -TIMETIME_OF_DAY
DATE_AND_TIME+, -TIMEDATE_AND_TIME
TIME_OF_DAY-TIME_OF_DAYTIME
DATE-DATETIME
DATE_AND_TIME-DATE_AND_TIMETIME
TIME*, /a numberTIME
a number*TIMETIME

The long family has the same table with LTIME, LTIME_OF_DAY, LDATE, and LDATE_AND_TIME. A moment of a day wraps around midnight, so TOD#23:59:50 + T#20s is TOD#00:00:10. Any other combination, such as two points in time added together or a short type mixed with a long one, is rejected (E156); convert first, for example with TIME_TO_LTIME.

The functions ADD, SUB, MUL, and DIV take the same combinations, and ADD and MUL take any number of arguments, folded from the left: ADD(stamp, T#1s, T#2s) is stamp + T#1s + T#2s.

The compiler carries these operations out with the standard library, ADD_DT_TIME for DATE_AND_TIME + TIME, MUL_TIME__LINT for TIME * n, and so on, so a project that calculates with time values must link iec61131std (see Linking and Libraries). Each of these functions can also be called directly.

A duration plus or minus a bare integer compiles too, and reads the integer as what the type counts: cycle + 5 adds five milliseconds to a TIME and five nanoseconds to an LTIME. The compiler warns about it (E157), because the unit is only implied; cycle + T#5ms says the same without the warning.

A negative duration does not fit into the unsigned TIME. A literal such as T#-10s still compiles, but the compiler warns about an underflow and the value wraps around to a large positive duration. Use LTIME when a duration must be able to go below zero: LT#-10s is a negative LTIME and gets no warning.

To read a time value as a number, convert it with a cast. DINT#cycle gives the milliseconds of a TIME, because that is what the type holds.

The standard library converts between the families and to text, for example TIME_TO_LTIME and TIME_TO_STRING, and it brings the timers TON, TOF, and TP, which are function blocks. The standard library reference lists them.

What’s next

The next chapter builds bigger types out of the ones so far: arrays, structs, and enumerations.