【问题标题】:SNMP EventTime in Human Readable format in JavaJava 中人类可读格式的 SNMP EventTime
【发布时间】:2012-03-14 10:24:09
【问题描述】:

我有一个独立的 java 应用程序,它通过 SNMP 陷阱接收 SNMP 消息。我在我的应用程序中使用 SNMP4J 库。在收到的 SNMP 消息中,我需要将十六进制格式的事件时间字段转换为人类可读的格式。接收到的事件时间字段通常如下所示:

      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 

谁能告诉我如何在有或没有 SNMP4J 库的帮助下将文本“07 DC 03 0C 12 15 2C 1F 2B 01 00”转换为人类可读的日期时间值?谢谢。

【问题讨论】:

  • 更准确地说,我需要从这个十六进制数字序列中获取一个 java.util.Date 对象。我想知道是否有办法做到这一点。

标签: java snmp snmp4j


【解决方案1】:

你可以使用 Integer.parseInt("07dc", 16) 和 2012 年的 pops,所以这应该会暗示这一年,其余的我相信你会自己弄清楚这是否确实是这一年。

【讨论】:

  • String[] tmp = (pdu.getVariableBindings().get(8)).toValueString().split(":"); String eventTime = getTimeStampAsText(tmp);
  • 私有同步 String getTimeStampAsText(String[] strArray){ String hyear, hmonth, hday, hhour, hmin, hmil; int dyear、dmonth、dday、dhour、dmin、dmil; hyear = strArray[0] + strArray[1]; hmonth = strArray[2]; hday = strArray[3];
  • hhour = strArray[4]; hmin = strArray[5]; hmil = strArray[6]; dyear = Integer.parseInt(hyear, 16); dmonth = Integer.parseInt(hmonth, 16); dday = Integer.parseInt(hday, 16); dhour = Integer.parseInt(hhour, 16); dmin = Integer.parseInt(hmin, 16); dmil = Integer.parseInt(hmil, 16);返回 dyear + "-" + dmonth + "-" + dday + " " + dhour + ':' + dmin + ':' + dmil; }
  • @Fardaarda 为什么不创建一个新帖子而不是输入代码作为 cmets?
【解决方案2】:

也许有点晚了(你在 6 年前发布了你的问题)但我最近遇到了同样的问题并找到了一个考虑到的通用解决方案:
1. SNMP 回复可能会或可能不会报告与 GMT 的偏移量
2.如果报时区,可能与我们当地时区不同

/**********************************************************************************************************************
 * 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

【讨论】:

    【解决方案3】:

    我正在使用现代 Java 日期和时间 API java.time 提供现代答案。

    十六进制字符串由以下字段组成:

    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
    

    我在一个重复的问题中写了这个答案,其中示例 SNMP 事件时间字符串是07e4070e04032b。所以我假设一个十六进制字符串,字节之间没有空格。从 Robert Koch 的回答和从那个重复的问题看来,并非所有 11 个字节都需要存在(示例字符串的长度为 7 个字节)。所以我的转换考虑了长度 6、7、8、10 和 11。

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

    我们来试试吧:

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

    输出是:

    2020-07-14T04:03:43

    链接

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-30
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多