uuuu-MM-dd
Edit: This fixes it. I am using java.time, the modern Java date and time API, and Java syntax.
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss[.SSS]xxx", Locale.ROOT);
Trying it out:
String[] variants = {
"2017-04-17 20:33:45.223+05:30",
"2017-04-17 20:33:45+05:30",
// Variants we don’t want to accept
"2017-04-17 20:00+05:30",
"2017-04-17 20:00:00.000000+05:30" };
for (String inputString : variants) {
try {
OffsetDateTime dateTime = OffsetDateTime.parse(inputString, FORMATTER);
System.out.println("Parsed: " + dateTime);
} catch (DateTimeParseException dtpe) {
System.out.println("Invalid: " + inputString);
}
}
Output:
Parsed: 2017-04-17T20:33:45.223+05:30
Parsed: 2017-04-17T20:33:45+05:30
Invalid: 2017-04-17 20:00+05:30
Invalid: 2017-04-17 20:00:00.000000+05:30
What went wrong in your code?
You had the right idea for your purpose.
You attempted using the outmoded Joda-Time library. Joda-Time can support optional parts when parsing, but not through the square bracket syntax. Instead its DateTimeFormatterBuilder has got an appendOptional method.
In your java.time code this part of your format pattern string doesn’t match any of your inputs: MM/dd/yyyy. Java parsed 20 as a 2 digit month number (postponing validation of the number) and threw the exception because no slash was found after 20.
Edit 2: why xxx works but Z doesn't:
With Joda-Time’s DateTimeFormat one Z is for offset without colon, for example +0530. ZZ should have worked for +05:30 with colon.
With java.time both x and Z (and also upper case X) are for zone offset. Here too Z is for offset without colon. Either xxx or ZZZZZ works for +05:30.
Use the built-in formatters
Original answer, likely useful for others: This one does it (using Java syntax):
private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendOffsetId()
.toFormatter();
Let’s try it out:
String[] variants = {
"2017-04-17 20:33:45.223+05:30",
"2017-04-17 20:33:45+05:30",
"2017-04-17 20:00+05:30",
"2017-04-17 20:00:00.000000+05:30" };
for (String inputString : variants) {
OffsetDateTime dateTime = OffsetDateTime.parse(inputString, FORMATTER);
System.out.println(dateTime);
}
Output:
2017-04-17T20:33:45.223+05:30
2017-04-17T20:33:45+05:30
2017-04-17T20:00+05:30
2017-04-17T20:00+05:30
I am exploiting the fact that the built-in DateTimeFormatter.ISO_LOCAL_TIME accepts a time both with and without decimals on the seconds. We can reuse existing formatters in our own formatter through a DateTimeFormatterBuilder.