When I parse using yyyy-MM-dd'T'HH:mm:ss it works fine, but when I
parse yyyy-MM-dd'T'HH:mm:ssXXX a ParseException is thrown.
Which is the correct format to parse the date and also what exactly is
the difference between these two formats?
Let's first look into yyyy-MM-dd'T'HH:mm:ss:
Check the following line (emphasis mine) from the documentation:
Parses text from the beginning of the given string to produce a date.
The method may not use the entire text of the given string.
So, basically, the format, yyyy-MM-dd'T'HH:mm:ss is considering only up to 2014-12-03T10:05:59 and ignoring the fraction of second and timezone offset information.
What is wrong with yyyy-MM-dd'T'HH:mm:ssXXX?
In this format, you have put the symbol for timezone offset correctly but missed the symbols for fraction of a second.
What is the correct format to parse it using SimpleDateFormat?
The short answer: None
Long answer: SimpleDateFormat can not handle a precision beyond milliseconds (i.e. 3 digits after .) correctly and therefore none of the formats can parse it correctly. The only way to get it correct is by keeping the digits after . up to three digits e.g. 2014-12-03T10:05:59.564+08:00, 2014-12-03T10:05:59.56+08:00 etc. Let's see how SimpleDateFormat will parse 2014-12-03T10:05:59.5646+08:00 erroneously.
SimpleDateFormat considers the digits after . as the number of milliseconds (instead of fraction of a second, the way the modern date-time API considers). Thus, the calculation goes like this:
5646 milliseconds = 5 seconds + 646 milliseconds
2014-12-03T10:05:59 + 5 seconds + 646 milliseconds = 2014-12-03T10:06:04.646
Let's validate it using the code:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String strDateTime = "2014-12-03T10:05:59.5646+08:00";
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
Date date = sdf.parse(strDateTime);
sdf.setTimeZone(TimeZone.getTimeZone("GMT+08:00"));
System.out.println(sdf.format(date));
}
}
Output:
2014-12-03T10:06:04.646+08:00
java.time
With the release of Java SE 8 in March 2014, the outdated and error-prone legacy Date-Time API (java.util Date-Time types and their formatting type, SimpleDateFormat etc.) was supplanted by java.time, the modern Date-Time API*. It is strongly recommended to stop using the legacy API and switch to this new API.
Solution using java.time, the modern API:
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.parse("2014-12-03T10:05:59.5646+08:00");
System.out.println(odt);
}
}
Output:
2014-12-03T10:05:59.564600+08:00
Isn't it cool?
The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.
By the way, for any reason, if you need to convert this object of OffsetDateTime to an object of java.util.Date, you can do so as follows:
Date date = Date.from(odt.toInstant());
Learn more about java.time, the modern Date-Time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.