Gson: java.text.ParseException: Unparseable date:

2019-03-05 04:52发布

问题:

How can I parse a string date in the format:

"2018-04-09T09:00:00+02:00"

Gson uses:

new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)

But it gives the following exception:

    com.google.gson.JsonSyntaxException: 2018-04-09T09:00:00+02:00
    at com.google.gson.DefaultDateTypeAdapter.deserializeToDate(DefaultDateTypeAdapter.java:107)
    at com.google.gson.DefaultDateTypeAdapter.deserialize(DefaultDateTypeAdapter.java:82)
    at com.google.gson.DefaultDateTypeAdapter.deserialize(DefaultDateTypeAdapter.java:35)
    at com.google.gson.TreeTypeAdapter.read(TreeTypeAdapter.java:58)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:95)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:183)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:95)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:183)
    at com.google.gson.Gson.fromJson(Gson.java:805)
    at com.google.gson.Gson.fromJson(Gson.java:743)
    ... 35 more
Caused by: java.text.ParseException: Unparseable date: "2018-04-09T09:00:00+02:00"
    at java.text.DateFormat.parse(DateFormat.java:337)
    at com.google.gson.DefaultDateTypeAdapter.deserializeToDate(DefaultDateTypeAdapter.java:105)
    ... 52 more

Thanks in advance.

回答1:

You put the Z inside quotes ('Z'). If you take a look at the javadoc, you'll see that:

Text can be quoted using single quotes (') to avoid interpretation

This means that your formatter is expecting the letter Z (and not some other value like +02:00), and that's why you're getting the error.

In the same javadoc page we can see that the pattern letter to parse offsets (the +02:00 part) is X, so your formatter should be like this:

new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.US);

As noticed in the comments, the pattern X was introduced only in java 7. In older versions, the only way is to split the string and set the offset in the formatter as a TimeZone:

String input = "2018-04-09T09:00:00+02:00";
Pattern pattern = Pattern.compile("(.*)([\\+|\\-]\\d{2}:\\d{2})");
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
    // timezone will be GMT+02:00
    sdf.setTimeZone(TimeZone.getTimeZone("GMT" + matcher.group(2)));
    // parse date without the offset part
    Date date = sdf.parse(matcher.group(1));
}

As said in the comments, you can also use the threeten backport: http://www.threeten.org/threetenbp/

That's a backport to java 8's date/time classes, and it's much better and easier to use:

OffsetDateTime odt = OffsetDateTime.parse("2018-04-09T09:00:00+02:00");

And if you still need to use java.util.Date, is easy to do the conversion:

Date date = DateTimeUtils.toDate(odt.toInstant());