Update
Thanks to Ole V.V. for suggesting this simpler pattern:
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendPattern("[XXX][XX][X]")
.toFormatter(Locale.ENGLISH);
The original answer is still useful if the units (e.g. month, day, hour etc.) can be in single-digit or double-digit. This alternative pattern will fail in case units are in single-digit.
Original answer
The solution is to use a DateTimeFormatter
with optional patterns. The DateTimeFormatter
allows us to specify optional patterns in the square bracket.
Demo:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(
"u-M-d'T'H:m:s[.[SSSSSSSSS][SSSSSSSS][SSSSSSS][SSSSSS][SSSSS][SSSS][SSS][SS][S]][XXX][XX][X]",
Locale.ENGLISH);
// Test
Stream.of(
"2021-07-22T20:10:15+0000",
"2021-07-22T20:10:15+00:00",
"2021-07-22T20:10:15+00",
"2021-07-22T20:10:15.123456789+0000",
"2021-07-22T20:10:15.12345678+0000",
"2021-07-22T20:10:15.123+0000",
"2021-07-22T20:10:15.1+0000"
).forEach(s -> System.out.println(OffsetDateTime.parse(s, dtf)));
}
}
Output:
2021-07-22T20:10:15Z
2021-07-22T20:10:15Z
2021-07-22T20:10:15Z
2021-07-22T20:10:15.123456789Z
2021-07-22T20:10:15.123456780Z
2021-07-22T20:10:15.123Z
2021-07-22T20:10:15.100Z
The Z
in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC
timezone (which has the timezone offset of +00:00
hours).
Learn more about the modern Date-Time API from Trail: Date Time.
Check the documentation page of DateTimeFormatter
for the complete list of pattern letters.
OffsetDateTime.parse(dateString.replaceFirst("\\+(\\d{2})(\\d{2})", "+$1:$2"))
– Murky