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