Convert snmp octet string to human readable date format

北慕城南 提交于 2019-12-03 14:21:51

You can find the format specification here.

A date-time specification. 
            field  octets  contents                  range
            -----  ------  --------                  -----
              1      1-2   year*                     0..65536
              2       3    month                     1..12
              3       4    day                       1..31
              4       5    hour                      0..23
              5       6    minutes                   0..59
              6       7    seconds                   0..60
                           (use 60 for leap-second)
              7       8    deci-seconds              0..9
              8       9    direction from UTC        '+' / '-'
              9      10    hours from UTC*           0..13
             10      11    minutes from UTC          0..59
* Notes:
            - the value of year is in network-byte order
            - daylight saving time in New Zealand is +13 For example, 
              Tuesday May 26, 1992 at 1:30:15 PM EDT would be displayed as:
                 1992-5-26,13:30:15.0,-4:0 
              Note that if only local time is known, then timezone
              information (fields 8-10) is not present.

In order to decode your sample data you can use this quick-and-dirty one-liner:

>>> import struct, datetime
>>> s = '\x07\xd8\t\x17\x03\x184\x00'
>>> datetime.datetime(*struct.unpack('>HBBBBBB', s))
datetime.datetime(2008, 9, 23, 3, 24, 52)

The example above is far from perfect, it does not account for size (this object has variable size) and is missing timezone information. Also note that the field 7 is deci-seconds (0..9) while timetuple[6] is microseconds (0 <= x < 1000000); the correct implementations is left as an exercise for the reader.

[update]

8 years later, lets try to fix this answer (am I lazy or what?):

import struct, pytz, datetime

def decode_snmp_date(octetstr: bytes) -> datetime.datetime:
    size = len(octetstr)
    if size == 8:
        (year, month, day, hour, minutes, 
         seconds, deci_seconds,
        ) = struct.unpack('>HBBBBBB', octetstr)
        return datetime.datetime(
            year, month, day, hour, minutes, seconds, 
            deci_seconds * 100_000, tzinfo=pytz.utc)
    elif size == 11:
        (year, month, day, hour, minutes, 
         seconds, deci_seconds, direction, 
         hours_from_utc, minutes_from_utc,
        ) = struct.unpack('>HBBBBBBcBB', octetstr)
        offset = datetime.timedelta(
            hours=hours_from_utc, minutes=minutes_from_utc)
        if direction == b'-':
            offset = -offset 
        return datetime.datetime(
            year, month, day, hour, minutes, seconds, 
            deci_seconds * 100_000, tzinfo=pytz.utc) + offset
    raise ValueError("The provided OCTETSTR is not a valid SNMP date")

I'm not sure I got the timezone offset right but I don't have sample data to test, feel free to amend the answer or ping me in the comments.

@Paulo Scardine: This was the best answer I found online when working to resolve a very similar problem. It still took me a little while to resolve my issue even with this answer, so I wanted to post a follow up answer that may add more clarity. (specifically the issue with the date having different length options).

The following piece of code connects to a server and grabs the system time and then outputs it as a string to illustrate the method.

import netsnmp
import struct
oid = netsnmp.Varbind('hrSystemDate.0')
resp = netsnmp.snmpget(oid, Version=1, DestHost='<ip>', Community='public')
oct = str(resp[0])
# hrSystemDate can be either 8 or 11 units in length.
oct_len = len(oct)
fmt_mapping = dict({8:'>HBBBBBB', 11:'>HBBBBBBcBB'})
if oct_len == 8 or oct_len == 11:
    t = struct.unpack(fmt_mapping[oct_len], oct)
    print 'date tuple: %s' % (repr(t))
else:
    print 'invalid date format'

I hope this helps other people who are having similar issues trying to work with this type of data.

Shameless plug here: The Pycopia SNMP and SMI modules correctly handle this object, and others as well. Pycopia is installed from source, and dont forget the mibs file if you try it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!