Decoding 12-Byte and 5-Byte COSEM Date/Time Formats
COSEM defines two standard timestamp representations: date_time (12 bytes) and time (4 bytes) / date (5 bytes).
12-Byte Date/Time Structure
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)
Python Parser Implementation
import struct
from datetime import datetime, timezone, timedelta
def parse_cosem_datetime(raw_bytes: bytes) -> 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(
">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