Python将 snmp 八位字节字符串转换为人类可读的日期格式

使用 pysnmp 框架,我通过 snmp walk 得到了一些值。不幸的是对于oid

1.3.6.1.21.69.1.5.8.1.2(文档-电缆-设备-MIB)

我得到一个奇怪的结果,我无法在这里正确打印,因为它包含像这样的 ascii 字符 BEL ACK

做repr时,我得到:

OctetString('\x07\xd8\t\x17\x03\x184\x00')

但输出应如下所示:

2008-9-23,3:24:52.0

该格式称为“DateAndTime”。如何将 OctetString 输出转换为“人类可读”的日期/时间?

17

您可以在此处找到格式规范。

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.

为了解码您的样本数据,您可以使用这个快速而肮脏的单行:

>>> 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)

上面的示例远非完美,它没有考虑大小(此对象具有可变大小)并且缺少时区信息。另请注意,字段 7 是分秒 (0..9) 而 timetuple[6] 是微秒 (0 <= x < 1000000);正确的实现留给读者作为练习

[更新]

8 年后,让我们尝试修复这个答案(我是懒惰还是什么?):

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")

我不确定我的时区偏移是否正确,但我没有要测试的样本数据,请随时修改答案或在评论中 ping 我。

10 年 12 月 31 日 19:50 回答
保罗·斯卡丁
60.8k1010金徽章117117银徽章139139枚铜牌
  • 请注意,此对象具有可变长度,因此此代码可能会针对某些对象失败,并错过时区信息。 —— 基思 2010 年 12 月 31 日 21:51
4

@Paulo Scardine:这是我在解决非常相似的问题时在网上找到的最佳答案。即使有了这个答案,我还是花了一点时间来解决我的问题,所以我想发布一个后续答案,可能会更加清晰。(特别是日期具有不同长度选项的问题)。

下面这段代码连接到服务器并抓取系统时间,然后将其作为字符串输出以说明该方法。

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'

我希望这可以帮助其他在尝试使用此类数据时遇到类似问题的人。

12 年 1 月 10 日 19:47 回答
泔水
1,91711个金徽章1515银徽章1111个青铜徽章
2

无耻的插件在这里:Pycopia SNMP 和 SMI 模块正确处理这个对象,以及其他。 Pycopia是从源代码安装的,如果您尝试,请不要忘记mibs 文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值