P2039¶
- Code
P2039
- Message
Duration literal is outside the range the duration type can represent
This error occurs when a duration literal names a length of time the type cannot hold.
A duration is stored as a signed count of milliseconds, so the durations a program can write are the ones that count reaches:
Type |
Storage |
Range |
|---|---|---|
TIME |
32-bit milliseconds |
|
LTIME |
64-bit milliseconds |
about ±292 million years |
The count is signed because a duration can be negative — subtracting one time from a later one gives a negative result.
A duration outside the range has no millisecond count to be stored as, so the compiler reports it rather than keeping the low bits, which would give a different duration than the one the program wrote — and often one with the opposite sign.
Example¶
The following code will generate error P2039:
PROGRAM main
VAR
timeout : TIME := T#30d;
END_VAR
END_PROGRAM
A TIME holds about 24.8 days, so 30 days is not a value it can take.
To fix this error, use a duration the type can hold:
PROGRAM main
VAR
timeout : TIME := T#20d;
END_VAR
END_PROGRAM
Or use LTIME, whose 64-bit count reaches far beyond any interval a control
program is likely to measure:
PROGRAM main
VAR
timeout : LTIME := LTIME#30d;
END_VAR
END_PROGRAM
LTIME requires IEC 61131-3 Edition 3. See
Edition Support.
Long intervals in a control program¶
A scan cycle is measured in milliseconds, so an interval of weeks is usually
better counted than timed. Where a program needs to measure days or months,
count elapsed cycles or completed days in an integer variable rather than
holding the whole span in one TIME:
PROGRAM main
VAR
day_elapsed : TIME := T#24h;
days_run : UDINT;
END_VAR
END_PROGRAM
This also keeps the value meaningful across a restart, which a running timer does not.
The literal names its own type¶
A duration literal is held to the range of the type its prefix names, not the
range of the variable it is stored into. T#30d is out of range even in an
LTIME variable, the same way INT#40000 is not an INT whatever it is
assigned to:
PROGRAM main
VAR
timeout : LTIME := T#30d; (* Error: T# names a TIME *)
END_VAR
END_PROGRAM
Write the prefix of the type you mean, as in LTIME#30d above.
Narrowing is reported too: an LTIME# literal does not fit a TIME
variable, which is reported as P4022.
See Also¶
Think IronPLC is wrong about this?
If you believe this diagnostic is incorrect, open an issue on GitHub with a small sample that demonstrates the problem.