SysTimeRtcGet reads the operating-system clock and returns a UTC count of seconds; check the result code, then convert with SysTimeRtcConvertUtcToDate and SysTimeRtcConvertUtcToLocal. The OS time service restores the clock after a power cut, so a networked controller needs no battery clock and no helper script.
You need no helper script and no battery-backed clock. The SysTime library in the CODESYS runtime exposes the controller's operating-system clock directly: SysTimeRtcGet returns the time as a UTC count of seconds, SysTimeRtcConvertUtcToDate turns that count into year, month, day and time fields, and SysTimeRtcConvertUtcToLocal applies the configured time zone and summer-time rules. Because the operating-system clock is the source, your code sees whatever the OS time service settles. On a networked controller, NTP restores the clock after every power cut, and the next read is correct. This page walks the whole chain in Structured Text, with the checks that keep an unsynchronized reading out of your records.
Which function reads the operating-system clock in CODESYS?
SysTimeRtcGet reads the controller's operating-system clock and hands you the whole date and time as one number, the seconds counted in UTC from 1 January 1970, so one library call replaces any script.
The three functions form one chain:
| Call | Gives you | Form |
|---|---|---|
| SysTimeRtcGet | The OS clock | UTC seconds since 1 January 1970 |
| SysTimeRtcConvertUtcToDate | Calendar fields | SYSTIMEDATE: year, month, day, hour, minute, second |
| SysTimeRtcConvertUtcToLocal | Local wall time | Seconds, shifted by the configured zone and summer-time rules |
The getter reads whatever the operating system holds, and the operating system's time service is what synchronizes that clock. The runtime converts; it never owns the source. That split is why the power-off case solves itself on a networked machine. Launching a helper script to fetch the time adds a process boundary, a formatting step and a handoff back into the runtime, and it still reads the same OS clock the library reaches in one call.
Does the controller need its own RTC to survive a power cut?
No, as long as the controller can reach a time server: this class of board ships with no battery-backed clock, the OS NTP service restores the clock after every reboot, and your next SysTimeRtcGet call reads the corrected value.
Power-off clears the clock on this class of single-board controller, because the board carries no battery-backed real-time clock (RTC). On reboot the OS brings the clock up wrong, NTP corrects it once the network is reachable, and from that moment the getter returns true time. Between those two states your code has to tell the difference, so gate every use of the value on two tests: the result code equals zero, and the seconds value sits above 1,700,000,000, the level the count passed on 14 November 2023. A controller that has not yet synced reports a small or absurd count, and the gate catches it before a wrong date reaches a record.
The one case this design fails is a machine on an isolated network with no reachable time server. There, fit a battery-backed RTC module or have an operator set the clock at startup, and treat every power cut as a clock reset until one of those is in place.
What do I need before writing the code?
You need the SysTime library available to the runtime, an OS clock already corrected by NTP, and four variables: the UTC seconds, the result code, the date structure, and the local seconds.
- A runtime whose library manager resolves the SysTime functions. A call that will not compile points at the library reference or the runtime version; the runtime's documentation lists what it carries.
- An OS clock already corrected. Check the date the controller reports in its system information before you debug any conversion; if the OS date is wrong, fix the time service there first.
- Declarations for the chain:
udiUtcTime : UDINT; // UTC seconds from the getter
udiUtcTimeLocal : UDINT; // local seconds after conversion
udiResult : UDINT; // zero when the call succeeded
strTimeDate : SYSTIMEDATE; // year, month, day, hour, minute, second
xTimeValid : BOOL; // your gate flag
Match the types to the library version your runtime documents; the udi prefix marks the unsigned 32-bit integers.
How do I read and convert the time in Structured Text?
Read the clock first, confirm the result code came back zero, then run the two conversions in order; any nonzero code stops the chain before a bad timestamp reaches your logic or your records.
- Read the clock:
udiUtcTime := SysTimeRtcGet(udiResult);captures the seconds and the result code in one call. - Test the code. If udiResult differs from zero, clear xTimeValid and leave; the documentation of your runtime lists the codes.
- Fill the calendar fields:
udiResult := SysTimeRtcConvertUtcToDate(udiUtcTime, strTimeDate);. - Shift to local time:
udiResult := SysTimeRtcConvertUtcToLocal(udiUtcTime, udiUtcTimeLocal);. - Use the outputs deliberately: strTimeDate where an operator reads the time, udiUtcTime for storage, ordering and comparisons.
The complete chain:
udiUtcTime := SysTimeRtcGet(udiResult);
IF udiResult <> 0 THEN
xTimeValid := FALSE;
RETURN;
END_IF
udiResult := SysTimeRtcConvertUtcToDate(udiUtcTime, strTimeDate);
IF udiResult <> 0 THEN
xTimeValid := FALSE;
RETURN;
END_IF
udiResult := SysTimeRtcConvertUtcToLocal(udiUtcTime, udiUtcTimeLocal);
xTimeValid := (udiResult = 0);
Treat a nonzero result anywhere in the chain as a failed read, and raise it through your normal diagnostics instead of continuing with the last old value.
Example: what does one read look like after a power cut?
A controller reboots at 04:30 UTC on 18 August 2025, NTP corrects the clock within seconds of the network coming up, and SysTimeRtcGet returns 1,755,491,400, which the two conversions turn into a 06:30 local stamp.
- Power returns. The OS clock comes up wrong, NTP corrects it, and the getter returns udiUtcTime = 1,755,491,400 with udiResult = 0. The value clears the 1.7-billion floor, so the clock has synced.
- SysTimeRtcConvertUtcToDate fills strTimeDate with 18 August 2025, 04:30:00.
- The site runs UTC+2 in summer, an offset of 2 × 3,600 = 7,200 s. SysTimeRtcConvertUtcToLocal returns 1,755,491,400 + 7,200 = 1,755,498,600, which reads 06:30:00 local.
- The board also shows time into the morning shift. The shift began at 06:00 local, that is 04:00 UTC, that is 1,755,489,600 s. The stamp minus the start is 1,755,498,600 - 1,755,489,600 = 9,000 s, so the line reads 2 h 30 min into the shift.
The same subtraction pattern, worked on a control platform that counts seconds from a fixed hour, is shown in a seconds-since-8AM counter walkthrough.
How do I check the read is correct?
Compare the converted fields with the controller's own clock report and hold the reading against a plausibility window: in 2025 a correct value sits near 1.75 billion seconds, and anything under 1.7 billion means the clock is unsynchronized or the call failed.
Run these checks in order:
- The controller's system information shows today's date. Wrong there, every value downstream is wrong; fix the OS time service.
- Every call in the chain returned udiResult = 0.
- The year field in strTimeDate reads the current year, 2025 in the example above.
- Local minus UTC equals your zone's offset. Subtract the two values and expect 3,600 s per hour of zone; the example pair gives 1,755,498,600 - 1,755,491,400 = 7,200 s for a UTC+2 summer day.
- A value under 1,700,000,000 fails the plausibility gate, so hold the invalid flag up and stamp nothing.
If the OS clock is wrong, the fix belongs at the OS time service. If the OS clock is right and the calls still fail, the function set carried by the runtime is the place to look, in the library documentation for your version.
Why is my time off by exactly 3,600 seconds?
An exact gap of 3,600 seconds means you are reading UTC where you expected local time: SysTimeRtcGet always returns UTC, and only SysTimeRtcConvertUtcToLocal applies your configured time zone and summer-time rules.
The local conversion follows the time zone and summer-time settings configured on the controller, so check that configuration when the offset is wrong. Adding a manual offset in code on top of the converted value counts the zone twice. A gap that appears on the two changeover weekends each year points at the summer-time rules; a constant multi-hour gap points at the zone setting itself. Store UTC, convert at the point of display, and both symptoms stay diagnosable from one subtraction.
How do I show the time on a shop-floor screen?
Size the clock text for the farthest reader: plan on 30 ft of viewing distance per inch of capital letter, 20 ft per inch for fast reading on the move, so a line read from 20 ft wants capitals of 0.67 to 1 in.
A clock line at a station read from 20 ft: at 30 ft per inch that is 20 / 30 = 0.67 in capitals, a full 1 in with the safer 20 ft per inch rule. Set line spacing at 1.7 times the capital height so a two-line stamp, time over date, stays readable.
Where the value goes matters as much as its size. A ticking clock or a live seconds-into-shift counter needs a screen that renders live data; live factory data on a dashboard or on signage draws that line. When the board only carries the standing schedule and the date, read-only process display specs for a plant cover the screen side, and shop-floor signage displays play that content offline from a card. For moving these seconds into the values a screen actually shows, PLC timestamp unit conversion for factory displays covers the arithmetic.
Recommendation: read the clock with SysTimeRtcGet on any controller that can reach a time server, gate every use of the value on a zero result code and a reading above 1,700,000,000 seconds, keep UTC for storage and ordering, and convert to local only where an operator reads the time. Fit a battery-backed RTC only when the machine runs with no reachable time server.
Questions
Can I set the clock from CODESYS instead of using NTP?
Yes. The same SysTime library provides SysTimeRtcSet, which writes the clock the getter reads. On a networked controller, leave NTP as the master: it corrects the clock after every power cut with no logic of yours involved. Use SysTimeRtcSet where an operator enters time on an isolated machine, and keep gating readings on the plausibility floor until the next sync.
How often should I call SysTimeRtcGet?
Call it in the task cycle that uses the value; there is no warm-up or minimum interval to respect. Wall-clock seconds advance once per second, so calling faster only re-reads the same number. For timing between two events inside your logic, use the library's high-resolution getter, SysTimeRtcHighResGet, instead of subtracting two wall-clock readings.
What is the largest value the seconds counter reaches?
In an unsigned 32-bit UDINT, the counter holds up to 4,294,967,295 seconds, which falls on 7 February 2106. A signed 32-bit variable would stop one second past 2,147,483,647, on 19 January 2038, so declare the seconds as UDINT and the 2038 limit never reaches your project.
Does the timestamp stay valid through a power cut?
No. Power-off drops the clock, and after reboot the OS clock runs wrong until NTP corrects it. Keep stamping only readings that pass both checks: result code zero and a value above 1,700,000,000 seconds, the level passed on 14 November 2023. Records written before sync should carry an invalid flag, never a wrong date.
Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.