In this method if string DATE returns NULL and try to split the string JAVA gives me an exception out of range index 4.
public static <T extends Enum<T>> String getDateString(WmiResult<T> result, T property, int index) {
if (result.getCIMType(property) == Wbemcli.CIM_DATETIME) {
String date = getStr(result, property, index);
return date.substring(0, 4) + '-' + date.substring(4, 6) + '-' + date.substring(6, 8);
}throw new ClassCastException(String.format(CLASS_CAST_MSG, property.name(), "DateTime",
result.getCIMType(property), result.getVtType(property)));
}
I my case, fixed this way:
public static <T extends Enum<T>> String getDateString(WmiResult<T> result, T property, int index) {
if (result.getCIMType(property) == Wbemcli.CIM_DATETIME) {
String date = getStr(result, property, index);
if(date == null || date.length() < 8){
return Constants.UNKNOWN;
}else{
return date.substring(0, 4) + '-' + date.substring(4, 6) + '-' + date.substring(6, 8);
}
}throw new ClassCastException(String.format(CLASS_CAST_MSG, property.name(), "DateTime",
result.getCIMType(property), result.getVtType(property)));
}
Issue-Label Bot is automatically applying the label bug? to this issue, with a confidence of 0.66. Please mark this comment with :thumbsup: or :thumbsdown: to give our bot feedback!
Links: app homepage, dashboard and code for this bot.
The getStr() method does not return null, but it does return an empty String if the WMI result is null. We don't do length checking here, so that's a bug.
We previously did full parsing of the WMI DateString which relied on Java 8 that we removed for a simpler date parsing as above... we can definitely throw in a quick fix to check the length but a better long term solution is a full datetime parsing method.
I'm marking this issue for first-timers-only. That means that I will only accept a PR for this one from someone who's never contributed to open source before. This one is easy (but don't make that statement make you feel bad if you have a hard time with it, there's more to contributing to open source than changing lines of code, especially if it's your first time). I'll hold your hand through this if you need me to. :-)
See the above discussion: we need to do a length check on the String date returned from the getStr() method, as the substring() parsing relies on a length of at least 8.
Here are the steps to get a PR merged here.
getStr() returns a non-null String.Here's code to parse the returned value to an OffsetDateTime.
As an option to the check in the first comment, the getDateString method could be rewritten to just call this method, and conditionally return Unknown if the returned value matched the Epoch (probably sufficient to test for a year <= 1970) or turn it into a LocalDate otherwise.
Class variable:
private static final DateTimeFormatter CIM_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss.SSSSSSZZZZZ",
Locale.US);
Methods:
/**
* Gets a DateTime value from a WmiResult as an OffsetDateTime
*
* @param <T>
* WMI queries use an Enum to identify the fields to query, and
* use the enum values as keys to retrieve the results.
* @param result
* The WmiResult from which to fetch the value
* @param property
* The property (column) to fetch
* @param index
* The index (row) to fetch
* @return The stored value if non-null, otherwise an OffsetDateTime
* representing the Unix Epoch.
*/
public static <T extends Enum<T>> OffsetDateTime getDateTime(WmiResult<T> result, T property, int index) {
if (result.getCIMType(property) == Wbemcli.CIM_DATETIME) {
return cimDateTimeToOffset(getStr(result, property, index));
}
throw new ClassCastException(String.format(CLASS_CAST_MSG, property.name(), "DateTime",
result.getCIMType(property), result.getVtType(property)));
}
private static OffsetDateTime cimDateTimeToOffset(String cimDateTime) {
// Keep first 22 characters: digits, decimal, and + or - sign
// But alter last 3 characters from a minute offset to hh:mm
try {
// From WMI as 20160513072950.782000-420,
int tzInMinutes = Integer.parseInt(cimDateTime.substring(22));
// modified to 20160513072950.782000-07:00
LocalTime offsetAsLocalTime = LocalTime.MIN.plusMinutes(tzInMinutes);
return OffsetDateTime.parse(
cimDateTime.substring(0, 22) + offsetAsLocalTime.format(DateTimeFormatter.ISO_LOCAL_TIME),
CIM_FORMAT);
} catch (IndexOutOfBoundsException // if cimDate not 22+ chars
| NumberFormatException // if TZ minutes doesn't parse
| DateTimeParseException e) {
LOG.trace("Unable to parse \"{}\" as a DateTime", cimDateTime, e);
return OffsetDateTime.ofInstant(Instant.EPOCH, ZoneId.systemDefault());
}
}
Since nobody jumped on this and it's important to do, I'll knock it out myself....
Most helpful comment
Issue-Label Bot is automatically applying the label
bug?to this issue, with a confidence of 0.66. Please mark this comment with :thumbsup: or :thumbsdown: to give our bot feedback!Links: app homepage, dashboard and code for this bot.