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.
XXX
to represent milliseconds? I'm not seeing it anywhere inSimpleDateFormat
javadoc. – Hargrove