You cannot use an ISO formatter if you don't get an ISO String…
The problem seems to be the format of the offset you get, it is +H:mm instead of the one used in the ISO standard, that is +HH:mm. In words: It does not consider single-digit hours.
You will have to build a specific DateTimeFormatter for this situation.
Unfortunately, Java 8 does not support patterns with a single-digit representation of offset hours, but if you can use Java 9 or higher, you'll be able to define a DateTimeFormatter that considers zone offsets formatted as +H:mm:
Java 9+
public static void main(String[] args) {
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendOffset("+H:mm", "UTC")
.toFormatter(Locale.ENGLISH);
OffsetDateTime sourceDateTime = OffsetDateTime.parse("2019-08-07T19:20-5:00", dtf);
System.out.println(sourceDateTime.getOffset());
}
This uses the ISO formatter for a LocalDateTime and appends a specific pattern for parsing offsets.
Admittedly, I'm not sure if "UTC" is a good (hard-coded) choice as a default offset in case the String does not contain any.
Output of this code:
-05:00
Java 8 --> String manipulation
public static void main(String[] args) {
// provide some variants of input
List<String> variants = List.of(
"2019-08-07T19:20-5:00", "2019-08-07T19:20+5:00",
"2019-08-07T19:20-05:00", "2019-08-07T19:20+05:00"
);
// handle offset extraction via String manipulation for each variant
variants.forEach(variant -> {
String parseable = variant;
/*
* This assumes an offset always has a sign and
* a colon that separates hours and minutes.
*
* Get all their indexes in order to find the offset
*/
int lastIndexOfColon = variant.lastIndexOf(':');
int lastIndexOfMinus = variant.lastIndexOf('-');
int lastIndexOfPlus = variant.lastIndexOf('+');
/*
* Decide which sign actually leads the offset
* (it's either a plus or the very last minus).
* In either case insert a leading zero if the amount of digits/chars
* between '-'/'+' and ':' is 1, otherwise don't do anything…
*/
if (lastIndexOfMinus > lastIndexOfPlus && lastIndexOfMinus + 2 == lastIndexOfColon) {
parseable = variant.substring(0, lastIndexOfMinus + 1)
+ '0'
+ variant.substring(lastIndexOfMinus + 1);
} else if (lastIndexOfPlus + 2 == lastIndexOfColon) {
parseable = variant.substring(0, lastIndexOfPlus + 1)
+ '0'
+ variant.substring(lastIndexOfPlus + 1);
}
// then parse the manipulated String
OffsetDateTime odt = OffsetDateTime.parse(parseable);
// get the offset
ZoneOffset zoneOffset = odt.getOffset();
// and print some result
String msg = String.format("%s has an offset of %s", variant, zoneOffset);
System.out.println(msg);
});
}
The output of this example is
2019-08-07T19:20-5:00 has an offset of -05:00
2019-08-07T19:20+5:00 has an offset of +05:00
2019-08-07T19:20-05:00 has an offset of -05:00
2019-08-07T19:20+05:00 has an offset of +05:00
Another way could be to separate the offset part from the date and time and create a ZoneOffset.of(int, int) using parsed values left and right to the last colon. Parsing the date-time part and applying the offset afterwards could also lead to the desired result.