Adds S7DateTimeCodec static class implementing the six Siemens S7 date/time
wire formats:
- DTL (12 bytes): UInt16 BE year + month/day/dow/h/m/s + UInt32 BE nanos
- DATE_AND_TIME (8 bytes BCD): yy/mm/dd/hh/mm/ss + 3-digit BCD ms + dow
- S5TIME (16 bits): 2-bit timebase + 3-digit BCD count → TimeSpan
- TIME (Int32 ms BE, signed) → TimeSpan, allows negative durations
- TOD (UInt32 ms BE, 0..86399999) → TimeSpan since midnight
- DATE (UInt16 BE days since 1990-01-01) → DateTime
Mirrors the S7StringCodec pattern from PR-S7-A2 — codecs operate on raw byte
spans so each format can be locked with golden-byte unit tests without a
live PLC. New S7DataType members (Dtl, DateAndTime, S5Time, Time, TimeOfDay,
Date) are wired into S7Driver.ReadOneAsync/WriteOneAsync via byte-level
ReadBytesAsync/WriteBytesAsync calls — S7.Net's string-keyed Read/Write
overloads have no syntax for these widths.
Uninitialized PLC buffers (all-zero year+month for DTL/DT) reject as
InvalidDataException → BadOutOfRange to operators, rather than decoding as
year-0001 garbage.
S5TIME / TIME / TOD surface as Int32 ms (DriverDataType has no Duration);
DTL / DT / DATE surface as DriverDataType.DateTime.
Test coverage: 30 new golden-vector + round-trip + rejection tests,
including the all-zero buffer rejection paths and BCD-nibble validation.
Build clean, 115/115 S7 tests pass.
Closes#289
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>