I am trying to parse a date that looks like this:
2010-04-05T17:16:00Z
This is a valid date per http://www.ietf.org/rfc/rfc3339.txt. The 'Z' literal (quote) "imply that UTC is the preferred reference point for the specified time."
If I try to parse it using SimpleDateFormat and this pattern:
yyyy-MM-dd'T'HH:mm:ss
it will be parsed as a Mon Apr 05 17:16:00 EDT 2010
SimpleDateFormat
is unable to parse the string with these patterns:
yyyy-MM-dd'T'HH:mm:ssz
yyyy-MM-dd'T'HH:mm:ssZ
I can explicitly set the TimeZone to use on the SimpleDateFormat
to get the expected output, but I don't think that should be necessary. Is there something I am missing? Is there an alternative date parser?
This question is related to
java
datetime
parsing
timezone
simpledateformat
The restlet project includes an InternetDateFormat class that can parse RFC 3339 dates.
Though, you might just want to replace the trailing 'Z' with "UTC" before you parse it.
The date you are parsing is in ISO 8601 format.
In Java 7 the pattern to read and apply the timezone suffix should read yyyy-MM-dd'T'HH:mm:ssX
The 'X' only works if partial seconds are not present: i.e. SimpleDateFormat pattern of
"yyyy-MM-dd'T'HH:mm:ssX"
Will correctly parse
"2008-01-31T00:00:00Z"
but
"yyyy-MM-dd'T'HH:mm:ss.SX"
Will NOT parse
"2008-01-31T00:00:00.000Z"
Sad but true, a date-time with partial seconds does not appear to be a valid ISO date: http://en.wikipedia.org/wiki/ISO_8601
With regards to JSR-310 another project of interest might be threetenbp.
JSR-310 provides a new date and time library for Java SE 8. This project is the backport to Java SE 6 and 7.
In case you are working on an Android project you might want to checkout the ThreeTenABP library.
compile "com.jakewharton.threetenabp:threetenabp:${version}"
JSR-310 was included in Java 8 as the java.time.* package. It is a full replacement for the ailing Date and Calendar APIs in both Java and Android. JSR-310 was backported to Java 6 by its creator, Stephen Colebourne, from which this library is adapted.
According to last row on the Date and Time Patterns table of the Java 7 API
X Time zone ISO 8601 time zone -08; -0800; -08:00
For ISO 8601 time zone you should use:
so to parse your "2010-04-05T17:16:00Z" you can use either "yyyy-MM-dd'T'HH:mm:ssX" or "yyyy-MM-dd'T'HH:mm:ssXX" or "yyyy-MM-dd'T'HH:mm:ssXXX" .
System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2010-04-05T17:16:00Z"));
System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").parse("2010-04-05T17:16:00Z"));
System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse("2010-04-05T17:16:00Z"));
will correctly print out 'Mon Apr 05 13:16:00 EDT 2010'
Since java 8 just use ZonedDateTime.parse("2010-04-05T17:16:00Z")
The time zone should be something like "GMT+00:00" or 0000 in order to be properly parsed by the SimpleDateFormat - you can replace Z with this construction.
Java doesn't parse ISO dates correctly.
Similar to McKenzie's answer.
Just fix the Z
before parsing.
Code
String string = "2013-03-05T18:05:05.000Z";
String defaultTimezone = TimeZone.getDefault().getID();
Date date = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(string.replaceAll("Z$", "+0000"));
System.out.println("string: " + string);
System.out.println("defaultTimezone: " + defaultTimezone);
System.out.println("date: " + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).format(date));
Result
string: 2013-03-05T18:05:05.000Z
defaultTimezone: America/New_York
date: 2013-03-05T13:05:05.000-0500
I provide another answer that I found by api-client-library
by Google
try {
DateTime dateTime = DateTime.parseRfc3339(date);
dateTime = new DateTime(new Date(dateTime.getValue()), TimeZone.getDefault());
long timestamp = dateTime.getValue(); // get date in timestamp
int timeZone = dateTime.getTimeZoneShift(); // get timezone offset
} catch (NumberFormatException e) {
e.printStackTrace();
}
Installation guide,
https://developers.google.com/api-client-library/java/google-api-java-client/setup#download
Here is API reference,
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/util/DateTime
Source code of DateTime
Class,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/main/java/com/google/api/client/util/DateTime.java
DateTime
unit tests,
https://github.com/google/google-http-java-client/blob/master/google-http-client/src/test/java/com/google/api/client/util/DateTimeTest.java#L121
Under Java 8 use the predefined DateTimeFormatter.ISO_DATE_TIME
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime result = ZonedDateTime.parse("2010-04-05T17:16:00Z", formatter);
I guess its the easiest way
Instant.parse ( "2010-04-05T17:16:00Z" )
Your String complies with the ISO 8601 standard (of which the mentioned RFC 3339 is a profile).
The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them.
Instead use either the Joda-Time library or the new java.time package in Java 8. Both use ISO 8601 as their defaults for parsing and generating string representations of date-time values.
The java.time framework built into Java 8 and later supplants the troublesome old java.util.Date/.Calendar classes. The new classes are inspired by the highly successful Joda-Time framework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extra project. See the Tutorial.
The Instant
class in java.time represents a moment on the timeline in UTC time zone.
The Z
at the end of your input string means Zulu
which stands for UTC
. Such a string can be directly parsed by the Instant
class, with no need to specify a formatter.
String input = "2010-04-05T17:16:00Z";
Instant instant = Instant.parse ( input );
Dump to console.
System.out.println ( "instant: " + instant );
instant: 2010-04-05T17:16:00Z
From there you can apply a time zone (ZoneId
) to adjust this Instant
into a ZonedDateTime
. Search Stack Overflow for discussion and examples.
If you must use a java.util.Date
object, you can convert by calling the new conversion methods added to the old classes such as the static method java.util.Date.from( Instant )
.
java.util.Date date = java.util.Date.from( instant );
Example in Joda-Time 2.5.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ):
DateTime dateTime = new DateTime( "2010-04-05T17:16:00Z", timeZone );
Convert to UTC.
DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );
Convert to a java.util.Date if necessary.
java.util.Date date = dateTime.toDate();
Source: Stackoverflow.com