简体   繁体   中英

SNMP EventTime in Human Readable format in Java

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 the event time field, which is in hexadecimal format, into a human readable format. The event time field received normally looks as follows for example:

      eventTime*SNMPv2-SMI::enterprises.193.183.4.1.4.5.1.7.0 = Hex-STRING: 
07 DC 03 0C 12 15 2C 1F 2B 01 00 

Can anyone tell me how I can convert the text '07 DC 03 0C 12 15 2C 1F 2B 01 00' into a human readable datetime value with or without the help of SNMP4J library? Thanks.

Maybe it's a bit late (you posted your question 6 years ago) but I recently got the same problem and found a general solution that takes into account:
1. The SNMP-reply may or may not report the offset from GMT
2. If the time zone is reported, it may be different from our local time zone

/**********************************************************************************************************************
 * Import definitions
 *********************************************************************************************************************/
import java.text.SimpleDateFormat;
import java.util.*;

/**********************************************************************************************************************
 * Class converting an SNMP DateAndTime into something readable.
 *********************************************************************************************************************/
public class ConvertDateAndTime
{
  /********************************************************************************************************************
   * This method converts the specified octet string into an array of bytes.
   * <br>The string should be a number of 2-char hexadecimal bytes values separated by any non-hexadecimal character.
   *
   * @param  value_ipar The value returned by the equipment.
   * @return            The value as an array of bytes.
   * @throws Exception  Thrown in case of an error
   *******************************************************************************************************************/
  public static int[] octetStringToBytes(String value_ipar)
  {
    // ---------------------------
    // Split string into its parts
    // ---------------------------
    String[] bytes;
    bytes = value_ipar.split("[^0-9A-Fa-f]");

    // -----------------
    // Initialize result
    // -----------------
    int[] result;
    result = new int[bytes.length];

    // -------------
    // Convert bytes
    // -------------
    int counter;
    for (counter = 0; counter < bytes.length; counter++)
      result[counter] = Integer.parseInt(bytes[counter], 16);

    // ----
    // Done
    // ----
    return (result);

  } // octetStringToBytes

  /********************************************************************************************************************
   * This method converts the 'DateAndTime' value as returned by the device into internal format.
   * <br>It returns <code>null</code> in case the reported year equals 0.
   * <br>It throws an exception in case of an error.
   *******************************************************************************************************************/
  public static Date octetStringToDate(String value_ipar)
    throws Exception
  {
    // ---------------------------
    // Convert into array of bytes
    // ---------------------------
    int[] bytes;
    bytes = octetStringToBytes(value_ipar);

    // -----------------------
    // Maybe nothing specified
    // -----------------------
    if (bytes[0] == 0)
      return (null);

    // ------------------
    // Extract parameters
    // ------------------
    int year;
    int month;
    int day;
    int hour;
    int minute;
    int second;
    int deci_sec = 0;
    int offset = 0;
    year = (bytes[0] * 256) + bytes[1];
    month = bytes[2];
    day = bytes[3];
    hour = bytes[4];
    minute = bytes[5];
    second = bytes[6];
    if (bytes.length >= 8)
      deci_sec = bytes[7];
    if (bytes.length >= 10)
    {
      offset = bytes[9] * 60;
      if (bytes.length >= 11)
        offset += bytes[10];
      if (bytes[8] == '-')
        offset = -offset;
      offset *= 60 * 1000;
    }

    // ------------------------------------
    // Get current DST and time zone offset
    // ------------------------------------
    Calendar calendar;
    int      my_dst;
    int      my_zone;
    calendar = Calendar.getInstance();
    my_dst = calendar.get(Calendar.DST_OFFSET);
    my_zone = calendar.get(Calendar.ZONE_OFFSET);

    // ----------------------------------
    // Compose result
    // Month to be converted into 0-based
    // ----------------------------------
    calendar.clear();
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.MONTH, month - 1);
    calendar.set(Calendar.DAY_OF_MONTH, day);
    calendar.set(Calendar.HOUR_OF_DAY, hour);
    calendar.set(Calendar.MINUTE, minute);
    calendar.set(Calendar.SECOND, second);
    calendar.set(Calendar.MILLISECOND, deci_sec * 100);

    // ---------
    // Reset DST
    // ---------
    calendar.add(Calendar.MILLISECOND, my_dst);

    // -----------------------------------------------------------------------------------
    // If the offset is set, we have to convert the time using the offset of our time zone
    // -----------------------------------------------------------------------------------
    if (offset != 0)
    {
      int delta;
      delta = my_zone - offset;
      calendar.add(Calendar.MILLISECOND, delta);
    }

    // -------------
    // Return result
    // -------------
    return (calendar.getTime());

  } // octetStringToDate

  /********************************************************************************************************************
   *                                               M A I N
   *******************************************************************************************************************/
  public static void main(String[] args)
  {
    try
    {
      SimpleDateFormat format;
      format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz");

      Date result;
      result = octetStringToDate("07 E2 02 02 12 0C 27 00"); // 18:12 in local time zone
      System.out.println(format.format(result)); // "2018-02-02 18:12:39 CET"

      result = octetStringToDate("07 E2 02 02 12 0C 27 00 2B 08 00"); // 18:12+08:00
      System.out.println(format.format(result)); // "2018-02-02 11:12:39 CET"

      result = octetStringToDate("07 E2 02 02 12 0C 27 00 2D 04 00"); // 18:12-04:00
      System.out.println(format.format(result)); // "2018-02-02 23:12:39 CET"

    }
    catch (Exception exception_ipar)
    {
      exception_ipar.printStackTrace();
    }

  } // main

} // class ConvertDateAndTime

你可以使用 Integer.parseInt("07dc", 16) 并输出 2012 年的流行音乐,所以这应该给出年份的暗示,其余的我相信你会自己弄清楚这是否确实是年份。

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM