SNMP EventTime in Human Readable format in Java

后端 未结 3 1257
走了就别回头了
走了就别回头了 2021-01-22 06:56

I have a stand alone java application that receives SNMP messages via an SNMP trap. I am using SNMP4J library in my application. In the SNMP message received, I need to convert

3条回答
  •  醉酒成梦
    2021-01-22 07:48

    I am providing the modern answer using java.time, the modern Java date and time API.

    The hex string consists of the following fields:

    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 (use 60 for leap-second)  0..60
      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
    

    I wrote this answer on the occasion of a duplicate question in which the example SNMP event time string was 07e4070e04032b. So I am assuming a hex string with no spaces between the bytes. It seems both from the answer by Robert Koch and from that duplicate question that not all 11 bytes need to be present (the example string is 7 bytes long). So my conversion takes lengths 6, 7, 8, 10 and 11 into account.

    public static Temporal decodeSnmpEventTime(String snmpEventTimeString) {
        if (snmpEventTimeString.length() % 2 != 0) {
            throw new IllegalArgumentException("Not a valid byte string, must have even length");
        }
        if (snmpEventTimeString.startsWith("00")
                || snmpEventTimeString.charAt(0) > '7') {
            throw new IllegalArgumentException(
                    "This simple implementation cannot handle years before year 256 nor after 32767;"
                                + " we need a different conversion to bytes"); 
        }
        
        byte[] bytes = new BigInteger(snmpEventTimeString, 16).toByteArray();
        
        int year = (bytes[0] & 0xFF) * 0x100 + (bytes[1] & 0xFF);
        int month = bytes[2] & 0xFF;
        checkRange(month, 1, 12);
        int dayOfMonth = bytes[3] & 0xFF;
        checkRange(dayOfMonth, 1, 31);
        int hour = bytes[4] & 0xFF;
        checkRange(hour, 0, 23);
        int minute = bytes[5] & 0xFF;
        checkRange(minute, 0, 59);
        int second = 0;
        int deciseconds = 0;
        if (bytes.length >= 7) {
            second = bytes[6] & 0xFF;
            checkRange(second, 0, 60); // 60 will cause conversion to fail, though 
            
            if (bytes.length >= 8) {
                deciseconds = bytes[7] & 0xFF;
                checkRange(deciseconds, 0, 9);
            }
        }
    
        LocalDateTime ldt = LocalDateTime.of(year, month, dayOfMonth,
                hour, minute, second, deciseconds * 100_000_000);
    
        if (bytes.length >= 9) { // there’s an offset
            char offsetSign = (char) (bytes[8] & 0xFF);
            int offsetHours = bytes[9] & 0xFF;
            checkRange(offsetHours, 0, 13); // allow 14 for all modern offsets
            int offsetMinutes = 0;
            if (bytes.length >= 11) {
                offsetMinutes = bytes[10] & 0xFF;
                checkRange(offsetMinutes, 0, 59);
            }
            
            ZoneOffset offset;
            if (offsetSign == '+') {
                offset = ZoneOffset.ofHoursMinutes(offsetHours, offsetMinutes);
            } else if (offsetSign == '-') {
                offset = ZoneOffset.ofHoursMinutes(-offsetHours, -offsetMinutes);
            } else {
                throw new IllegalArgumentException("Offset sign must be + or -, was " + offsetSign);
            }
            
            return ldt.atOffset(offset);
        } else {
            return ldt;
        }
    }
    
    private static void checkRange(int value, int min, int max) {
        if (value < min || value > max) {
            throw new IllegalArgumentException("Value " + value + " out of range " + min + ".." + max);
        }
    }
    

    Let’s try it out:

        String snmpEventTimeString = "07e4070e04032b";
        Temporal dateTime = decodeSnmpEventTime(snmpEventTimeString);
        System.out.println(dateTime);
    

    Output is:

    2020-07-14T04:03:43

    Links

    • SNMP date and time specification
    • Duplicate question: How do i get this Hex string converted to Date in java [duplicate]
    • Oracle tutorial: Date Time explaining how to use java.time.

提交回复
热议问题