Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DateFormat pattern "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" in Gson

I have two field like below (pay attention that the first field has milliseconds section):

{
  "updateTime":"2011-11-02T02:50:12.208Z",
  "deliverTime":"1899-12-31T16:00:00Z"
}

I want to deserialize the Json string to an object with Gson, so I get a Gson instance:

GsonBuilder gb = new GsonBuilder();
gb.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
gson = gb.create();

The first field is deserialized to Java date type: 2011-11-02 02:50:12.208 (looks like ignored the time zone section-‘Z’, that's I expected). However, the second field is deserialized to 1900-01-01 00:00:00 (I live in China, +8 GMT here), it seems that the time zone section-'Z' plays a part in deserialization.

Why the second field uses time zone section? It's not what I expected.

like image 305
Domi.Zhang Avatar asked Feb 16 '13 04:02

Domi.Zhang


People also ask

How to display current date and time using simpledateformat?

// displaying current date and time Calendar cal = Calendar.getInstance (); SimpleDateFormat simpleformat = new SimpleDateFormat ("E, dd MMM yyyy HH:mm:ss Z"); System.out.println ("Today's date and time = "+simpleformat.format (cal.getTime ())); Since we have used the Format and SimpleDateFormat class above, therefore import the following packages.

What is the correct date format for YYYYY?

Date Format [YYYY]-[MM]-[DD]T[HH]:[MM]:[SS]Z Date Format [YYYY]-[MM]-[DD]T[HH]:[MM]:[SS]Z Comments PostPosting GuidelinesFormatting

What are the packages to import when using format and simpledateformat?

Since we have used the Format and SimpleDateFormat class above, therefore import the following packages. With that, we have also used the Date − import java.text.Format; import java.text.SimpleDateFormat; import java.util.Date;

What is the format for converting regular expression to date format?

Regular Expression to Date Format [YYYY]-[MM]-[DD]T[HH]:[MM]:[SS]Z Toggle navigation RegEx TestingFrom Dan's Tools


1 Answers

Quick answer

First string is correctly parsed using your date format and your local time zone, second one does not respect it, so will be parsed by a default SimpleDateFormat object that has not milliseconds ("yyyy-MM-dd'T'HH:mm:ss'Z' is the parsing format) and uses UTC timezone giving you a "shift" in time part.

Full answer

To fully respond to your question you need to dive into Gson source code. More in particular you have to look at code of DefaultDateTypeAdapter that is used to parse dates. You can find all this code at link, but for quick reference I will copy here most relevant parts.

When you call this in the builder:

gb.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

you are initializing a DefaultDateTypeAdapter in this way:

DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
   this.enUsFormat = enUsFormat;
   this.localFormat = localFormat;
   this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
   this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
}

where:

  1. enUsFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") and
  2. localFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US)

since the string you have passed in the builder.

Pay attention that Locale.US is not a timezone and that iso8601Format is the same as enUsFormat without milliseconds but with UTC timezone.

Parsing happens into deserializeToDate method:

 private Date deserializeToDate(JsonElement json) {
    synchronized (localFormat) {
      try {
        return localFormat.parse(json.getAsString());
      } catch (ParseException ignored) {
      }
      try {
        return enUsFormat.parse(json.getAsString());
      } catch (ParseException ignored) {
      }
      try {
        return iso8601Format.parse(json.getAsString());
      } catch (ParseException e) {
        throw new JsonSyntaxException(json.getAsString(), e);
      }
    }
  }

where all of three date formats are used in a waterfall approach.

First Json string: "2011-11-02T02:50:12.208Z". It's parsed immediately by localFormat since has milliseconds and gives you the result you expect using your timezone.

Second Json string: "1899-12-31T16:00:00Z". It won't be parsed by localFormat since has not milliseconds, so second chance is enUsFormat that is the same pattern, except for the locale. So it will fail at the same way.

Last chance to parse: iso8601Format, it will, it has no milliseconds, BUT, for construction, it as also a UTC time zone, so it will parse date as UTC while the others parsed using your timezone.

like image 76
giampaolo Avatar answered Sep 19 '22 16:09

giampaolo