我有一个独立的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'转换为人类可读的日期时间值吗?感谢。
答案 0 :(得分:1)
你可以使用Integer.parseInt(“07dc”,16)和2012年的流行音乐,所以这应该给出一年的暗示,其余的我相信如果这确实是年份,你会自己弄清楚。
答案 1 :(得分:1)
也许它有点晚了(你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
答案 2 :(得分:0)
我正在使用现代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