SNMP EventTime в удобочитаемом формате на Java

У меня есть отдельное приложение 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 

Может ли кто-нибудь сказать мне, как я могу преобразовать текст «07 DC 03 0C 12 15 2C 1F 2B 01 00» в удобочитаемое значение даты и времени с помощью библиотеки SNMP4J или без нее? Спасибо.


person F. Aydemir    schedule 14.03.2012    source источник
comment
Точнее мне нужно получить объект java.util.Date из этой шестнадцатеричной последовательности чисел. Интересно, есть ли способ сделать это.   -  person F. Aydemir    schedule 14.03.2012


Ответы (3)


вы можете использовать Integer.parseInt("07dc", 16) и вне 2012 года, так что это должно дать намек на год, остальное, я уверен, вы сами догадаетесь, действительно ли это год.

person Carl-Emil Kjellstrand    schedule 14.03.2012
comment
String[] tmp = (pdu.getVariableBindings().get(8)).toValueString().split(:); Строка eventTime = getTimeStampAsText(tmp); - person F. Aydemir; 14.03.2012
comment
частная синхронизированная строка getTimeStampAsText(String[] strArray){ String hyear, hmonth, hday, hhour, hmin, hmil; int dyear, dmonth, dday, dhour, dmin, dmil; hyear = strArray[0] + strArray[1]; чмесяц = ​​strArray[2]; hday = strArray[3]; - person F. Aydemir; 14.03.2012
comment
ччас = strArray[4]; hmin = strArray[5]; hmil = strArray[6]; dyear = Integer.parseInt(hyear, 16); dmonth = Integer.parseInt (чмесяц, 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; } - person F. Aydemir; 14.03.2012
comment
@Fardaarda Почему бы вам не создать новый пост вместо того, чтобы вводить коды в качестве комментариев? - person ecle; 14.03.2012

Может быть, это немного поздно (вы разместили свой вопрос 6 лет назад), но недавно я столкнулся с той же проблемой и нашел общее решение, которое учитывает:
1. SNMP-ответ может сообщать или не сообщать о смещении от GMT< br> 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
person Robert Kock    schedule 02.02.2018

Я даю современный ответ, используя java.time, современный API даты и времени Java.

Шестнадцатеричная строка состоит из следующих полей:

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. Поэтому я предполагаю шестнадцатеричную строку без пробелов между байтами. Как из ответа Роберта Коха, так и из этого повторяющегося вопроса кажется, что не все 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

Ссылки

person Ole V.V.    schedule 14.07.2020