Skip to content

feat!: changed time to unsigned 32-bit preserving ltime as 64-bit#1801

Open
Angus-Bethke-Bachmann wants to merge 9 commits into
masterfrom
anbt/PRG-1747
Open

feat!: changed time to unsigned 32-bit preserving ltime as 64-bit#1801
Angus-Bethke-Bachmann wants to merge 9 commits into
masterfrom
anbt/PRG-1747

Conversation

@Angus-Bethke-Bachmann

@Angus-Bethke-Bachmann Angus-Bethke-Bachmann commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Please Note: Merge should be delayed until downstream dependent applications are prepared. This is a breaking change!

Changed

  • TIME, TIME_OF_DAY/TOD, DATE and DATE_AND_TIME/DT are now unsigned 32-bit.
  • LTIME, LTIME_OF_DAY/LTOD, LDATE and LDATE_AND_TIME/LDT remain 64-bit.
  • TIME and TIME_OF_DAY/TOD are represented as milliseconds.
  • DATE and DATE_AND_TIME/DT are represented as seconds.

Documentation

  • Updated to reflect the data type changes.

Testing

  • Updated existing tests to reflect the new 32-bit representation where necessary
  • Updated existing tests to reflect the milliseconds or seconds difference where nanoseconds was previously expected
  • Added some new tests to expand the coverage of the long time variants

PS: This is my first largely agent assisted PR, please take a look at it carefully. I found quite a few places where it had made assumptions I believed to be incorrect during my self-review, hopefully it was all of them.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Build Artifacts

🪟 Windows

Artifact Link Size
stdlib.lib Download 4.0 MB
stdlib.dll Download 0.1 MB
plc.exe Download 38.2 MB

From workflow run

🐧 Linux

Artifact Link Size
deb-x86_64 Download 38.4 MB
schema Download 0.0 MB
stdlib Download 32.4 MB
plc-x86_64 Download 43.4 MB
deb-aarch64 Download 30.8 MB
plc-aarch64 Download 43.3 MB

From workflow run

@ghaith ghaith changed the title feat: changed time to unsigned 32-bit preserving ltime as 64-bit feat!: changed time to unsigned 32-bit preserving ltime as 64-bit Jul 10, 2026
@ghaith

ghaith commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

since this is a beaking change, i updated the title to reflect that (feat!:)

@volsa volsa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Focused review — correctness and test-coverage only (skipping style/nits). Overall this is a solid, comprehensive breaking change and CI is green across x86_64/aarch64/Windows. A few correctness/semantics points and test gaps below that are worth a decision before merge.

pub extern "C-unwind" fn SUB_DATE_DATE(in1: i64, in2: i64) -> u32 {
let lhs = short_date_time_seconds(in1);
let rhs = short_date_time_seconds(in2);
checked_seconds_to_millis(lhs.wrapping_sub(rhs))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness — silent overflow for large date differences.

SUB_DATE_DATE/SUB_DT_DT return a TIME (u32 ms), which tops out at ~49.7 days. checked_seconds_to_millis uses wrapping_mul, so any date difference beyond that silently wraps to a garbage duration — no panic, no diagnostic. Previously this was i64 nanoseconds (~292-year range).

The wrapping_* choice looks intentional (the datetime_arithmetic_time.st lit test asserts -3000 for SUB_TIME underflow), but two issues remain:

  1. The doc comments on these short add/sub ops still say "Panic on overflow", which is now inaccurate.
  2. Large-diff overflow is untested.

Suggest documenting the ~49.7-day ms range limit (ideally saturate or validate instead of wrapping) and fixing the stale doc comments.

.unwrap()
.num_nanoseconds()
.unwrap()
pub extern "C-unwind" fn ADD_TIME(in1: i64, in2: i64) -> u32 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FFI signature mismatch (short variants).

The ST declaration is now FUNCTION ADD_TIME: TIME … IN1/IN2: TIME (32-bit), so the compiler emits this call with i32 arguments, while the Rust definition takes i64. It only works because short_time_millis masks with as u32, discarding the unspecified upper register bits — CI is green, so it holds on x86_64/aarch64/Windows — but it's an ABI mismatch that relies on register-passing coincidence and reads misleadingly (an i64 param that is really a u32).

Recommend changing the short-variant parameters to u32/i32 to match the ST-declared types (and dropping the now-redundant short_time_millis/short_date_time_seconds casts). Applies to all the short ADD_*/SUB_* functions in this file.

Comment thread src/typesystem.rs
name: TIME_TYPE.into(),
signed: true,
size: DATE_TIME_SIZE,
signed: false,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semantics — short TIME/TOD/DATE/DT are now unsigned.

With signed: false, negative durations no longer behave: T#1S - T#2S goes through wrapping_sub to ~4.29e9 ms, and comparisons/divisions on TIME are emitted as unsigned. IEC 61131-3 permits negative TIME.

The unit tests confirm this is a real behavior change — the old negative short-TIME cases (ADD_TIME(TIME#10s, TIME#-5s), SUB(TIME#10h50m, TIME#-10m)) were removed and migrated to LTIME. Is dropping negative short TIME intended? If so, should a negative short-TIME literal be rejected by validation rather than silently wrapping to a large positive value?

// SUB_DATE_DATE: DATE - DATE -> TIME (u32)
date1 := DATE#2024-01-15;
date2 := DATE#2024-01-10;
result := SUB_DATE_DATE(date1, date2);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test gap.

This covers a 5-day difference (fits in u32 ms), but there's no case for a difference beyond ~49.7 days — exactly where SUB_DATE_DATE silently wraps (wrapping_mul in checked_seconds_to_millis). Worth adding a large-diff case to pin down the intended overflow behavior.

a := ADD(TIME#5h,TIME#30s);
b := ADD_TIME(TIME#10s,TIME#-5s);
a := ADD(LTIME#5h,LTIME#30s);
b := ADD_LTIME(LTIME#10s,LTIME#-5s);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test gap — short-type arithmetic coverage moved to long variants.

This add_time test (and sub_time, sub_date, add_tod_time, add_dt_time, sub_tod_time, …) were all switched from the short types to LTIME/LDATE/LTOD/LDT. As a result the rewritten short-type paths — the new millisecond/second representation, unsigned handling, and wrapping_* overflow — are no longer exercised by these unit tests (only a couple of tests/lit/... cases cover them), and the negative short-TIME case that used to live here (ADD_TIME(TIME#10s, TIME#-5s)) is gone.

Consider keeping short-type variants of these tests alongside the new long ones so the 32-bit ms/second behavior stays covered at the unit level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants