简体   繁体   English

Java中人类可读格式的SNMP EventTime

[英]SNMP EventTime in Human Readable format in Java

I have a stand alone java application that receives SNMP messages via an SNMP trap.我有一个独立的 java 应用程序,它通过 SNMP 陷阱接收 SNMP 消息。 I am using SNMP4J library in my application.我在我的应用程序中使用 SNMP4J 库。 In the SNMP message received, I need to convert the event time field, which is in hexadecimal format, into a human readable format.在收到的 SNMP 消息中,我需要将十六进制格式的事件时间字段转换为人类可读的格式。 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?谁能告诉我如何在 SNMP4J 库的帮助下将文本 '07 DC 03 0C 12 15 2C 1F 2B 01 00' 转换为人类可读的日期时间值? 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:也许有点晚了(您 6 年前发布了您的问题)但我最近遇到了同样的问题,并找到了一个考虑到的通用解决方案:
1. The SNMP-reply may or may not report the offset from GMT 1. SNMP-reply 可能会或可能不会报告 GMT 的偏移量
2. If the time zone is reported, it may be different from our local time zone 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

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

I am providing the modern answer using java.time, the modern Java date and time API.我正在使用现代 Java 日期和时间 API java.time 提供现代答案。

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 .我在一个重复的问题中写了这个答案,其中示例 SNMP 事件时间字符串是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).从 Robert Koch 的回答和那个重复的问题看来,并非所有 11 个字节都需要存在(示例字符串的长度为 7 个字节)。 So my conversion takes lengths 6, 7, 8, 10 and 11 into account.所以我的转换考虑了长度 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);
    }
}

Let's try it out:让我们试试看:

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

Output is:输出是:

2020-07-14T04:03:43 2020-07-14T04:03:43

Links链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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