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

DATE, TOD and DT

TypeHeld asRange
DATEseconds since 1970-01-01, at midnight; unsigned 32-bitD#1970-01-01 .. D#2106-02-07
TODmilliseconds since midnight; unsigned 32-bitTOD#00:00:00 .. TOD#23:59:59.999
DTseconds since 1970-01-01 00:00; unsigned 32-bitDT#1970-01-01-00:00:00 .. DT#2106-02-07-06:28:15

CODESYS and TwinCAT hold them the same way. The default initial value of a DATE and a DT is 1970-01-01: Ed.3 Table 10 leaves it to an implementer whose calendar does not start at 0001-01-01. A literal that names no day or time, or one iecf cannot hold — before 1970, a TOD finer than a millisecond, a DT with a fraction of a second — is refused (E0020).

At the edges

(Implementer choices)

  • A TOD wraps at midnight, unflagged: a time of day is a clock.
  • A DATE or DT outside its range wraps and is flagged OVERFLOW, as an integer does; so does a difference outside TIME. A TIME holds ±24 days and 20 hours: the difference of two dates 25 days apart is already too much for it.
  • A DT holds whole seconds: milliseconds that come to one are dropped, rounding down, unflagged.
ExpressionTypeResultFlagNote
TOD#23:00:00 + T#2hTODTOD#01:00:00—wraps at midnight
TOD#01:00:00 - T#2hTODTOD#23:00:00—
TOD#01:00:00 - TOD#23:00:00TIMET#-22h—
DT#2026-11-07-22:00:00 + T#7hDTDT#2026-11-08-05:00:00—
DT#2026-11-07-12:00:00 + T#1500msDTDT#2026-11-07-12:00:01—ms dropped, rounding down
DT#2026-11-07-12:00:00 - T#1500msDTDT#2026-11-07-11:59:58—down, not toward zero
DT#1970-01-01-00:00:00 - T#1sDTDT#2106-02-07-06:28:15flag OVERFLOWwrapped
D#2026-12-01 - D#2026-11-07TIMET#24d—
D#2026-12-07 - D#2026-11-07TIMET#-19d17h2m47s296msflag OVERFLOW30 days: beyond TIME
SUB_DT_DT(DT#2026-11-07-12:00:00, DT#2026-11-07-11:00:00)TIMET#1h—
DT_TO_TOD(DT#2026-11-07-12:34:56)TODTOD#12:34:56—
DT_TO_DATE(DT#2026-11-07-12:34:56)DATED#2026-11-07—
CONCAT_DATE_TOD(D#2026-11-07, TOD#12:34:56.789)DTDT#2026-11-07-12:34:56—ms dropped
DAY_OF_WEEK(D#2026-11-07)USINT6—0 is Sunday (Ed.3 Table 36)
DAY_OF_WEEK(D#1970-01-01)USINT4—a Thursday
MAX(D#2026-11-07, D#2025-01-01)DATED#2026-11-07—

From parts and into them

CONCAT_DATE, CONCAT_TOD and CONCAT_DT (Ed.3 Table 36) take integers of any type. A part out of its range gives the type’s default value, flagged CONVERSION: a month not 1 to 12, a day not in its month, an hour not 0 to 23, a minute or second not 0 to 59, a millisecond not 0 to 999, or a date outside the type’s range. CODESYS’s DateConcat and PLCnext’s CONCAT_LDATE give the same (Implementer choices). A DT’s millisecond is checked, then dropped.

ExpressionTypeResultFlagNote
CONCAT_DATE(2026, 11, 8)DATED#2026-11-08—
CONCAT_DATE(2024, 2, 29)DATED#2024-02-29—a leap year
CONCAT_DATE(2023, 2, 29)DATED#1970-01-01flag CONVERSIONno such day
CONCAT_DATE(2026, 13, 1)DATED#1970-01-01flag CONVERSION
CONCAT_DATE(1969, 12, 31)DATED#1970-01-01flag CONVERSIONbefore the range
CONCAT_TOD(12, 34, 56, 789)TODTOD#12:34:56.789—
CONCAT_TOD(24, 0, 0, 0)TODTOD#00:00:00flag CONVERSION
CONCAT_TOD(12, 0, 0, 1000)TODTOD#00:00:00flag CONVERSION
CONCAT_DT(2026, 11, 8, 12, 34, 56, 789)DTDT#2026-11-08-12:34:56—ms dropped
CONCAT_DT(2106, 2, 7, 6, 28, 16, 0)DTDT#1970-01-01-00:00:00flag CONVERSIONpast the range

SPLIT_DATE, SPLIT_TOD and SPLIT_DT are statements of their own: each output takes any integer variable, and a part that does not fit it - the year in a USINT - wraps and is flagged CONVERSION, as any integer conversion does; one stored into a subrange is clamped and flagged, as any store into it. An output element out of bounds faults before any part is stored. With EN FALSE, IN is not evaluated and every output keeps its value; ENO is FALSE when EN is, or when a part did not fit its output (EN and ENO). Inside another call’s arguments they are not compiled yet (E0009). The harness’s splitwrap, splitclamp, splitindex and splitenable cases run each of these.

SPLIT_DT(IN := stamp, YEAR => y, MONTH => m, DAY => d, HOUR => h);