<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Parsing DLMS Octet-String Date/Time into ISO 8601 Strings]]></title><description><![CDATA[<h3>Decoding 12-Byte and 5-Byte COSEM Date/Time Formats</h3>
<p dir="auto">COSEM defines two standard timestamp representations: <code>date_time</code> (12 bytes) and <code>time</code> (4 bytes) / <code>date</code> (5 bytes).</p>
<h4>12-Byte Date/Time Structure</h4>
<pre><code class="language-text">Byte 0-1: Year (High byte, Low byte: 0x07EA = 2026, 0xFFFF = not specified)
Byte 2:   Month (1-12, 0xFE = Daylight saving start, 0xFD = Daylight saving end, 0xFF = not specified)
Byte 3:   DayOfMonth (1-31, 0xFD = 2nd from end, 0xFE = last day, 0xFF = not specified)
Byte 4:   DayOfWeek (1=Monday...7=Sunday, 0xFF = not specified)
Byte 5:   Hour (0-23, 0xFF = not specified)
Byte 6:   Minute (0-59, 0xFF = not specified)
Byte 7:   Second (0-59, 0xFF = not specified)
Byte 8:   Hundredths of second (0-99, 0xFF = not specified)
Byte 9-10:Deviation in minutes (Signed 16-bit, 0x8000 = not specified, e.g. +120 min = 0x0078)
Byte 11:  Clock Status (Bit 0: invalid, Bit 1: doubtful, Bit 2: different clock base, Bit 3: invalid status, Bit 7: daylight_saving_active)
</code></pre>
<h4>Python Parser Implementation</h4>
<pre><code class="language-python">import struct
from datetime import datetime, timezone, timedelta

def parse_cosem_datetime(raw_bytes: bytes) -&gt; str:
    if len(raw_bytes) != 12:
        raise ValueError("Invalid length for COSEM date_time")
    
    year, month, day, dow, hour, minute, sec, hundredths, dev, status = struct.unpack(
        "&gt;HBBBBBBBhB", raw_bytes
    )
    
    tz = timezone(timedelta(minutes=dev)) if dev != -32768 else timezone.utc
    dt = datetime(year, month, day, hour, minute, sec, hundredths * 10000, tzinfo=tz)
    return dt.isoformat()

# Example: 2026-08-22 14:30:00 UTC+8 (dev = +480 = 0x01E0)
raw = bytes.fromhex("07EA 08 16 FF 0E 1E 00 00 01E0 00")
print(parse_cosem_datetime(raw))
# Output: 2026-08-22T14:30:00+08:00
</code></pre>
]]></description><link>https://dlms.sharur.org/topic/35/parsing-dlms-octet-string-date-time-into-iso-8601-strings</link><generator>RSS for Node</generator><lastBuildDate>Fri, 16 Oct 2026 19:49:14 GMT</lastBuildDate><atom:link href="https://dlms.sharur.org/topic/35.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 22 Aug 2026 12:36:42 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Parsing DLMS Octet-String Date/Time into ISO 8601 Strings on Sat, 22 Aug 2026 12:36:43 GMT]]></title><description><![CDATA[<p dir="auto">Be careful with the sign of <code>Deviation</code>: In DLMS, <strong>positive deviation</strong> means the local time is <strong>ahead of UTC</strong> (e.g. UTC+8 is <code>+480</code> minutes). In some older proprietary systems, people mistakenly inverted the deviation sign.</p>
]]></description><link>https://dlms.sharur.org/post/81</link><guid isPermaLink="true">https://dlms.sharur.org/post/81</guid><dc:creator><![CDATA[david_miller]]></dc:creator><pubDate>Sat, 22 Aug 2026 12:36:43 GMT</pubDate></item></channel></rss>