【问题标题】:DateFormat pattern "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" in GsonGson 中的 DateFormat 模式“yyyy-MM-dd'T'HH:mm:ss.SSS'Z'”
【发布时间】:2013-02-01 03:36:06
【问题描述】:

我有两个如下所示的字段(注意第一个字段有毫秒部分):

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

我想用 Gson 将 Json 字符串反序列化为一个对象,所以我得到一个 Gson 实例:

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

第一个字段被反序列化为 Java 日期类型:2011-11-02 02:50:12.208(看起来忽略了时区部分 - “Z”,这是我的预期)。但是,第二个字段被反序列化为1900-01-01 00:00:00(我住在中国,这里是+8 GMT),似乎时区部分-'Z'起了作用参与反序列化。

为什么第二个字段使用时区部分?这不是我的预期。

【问题讨论】:

  • 对我来说,它无法解析第二个日期字符串 (java.text.ParseException: Unparseable date: "1899-12-31T16:00:00Z")。您使用的是哪个版本的 Gson?
  • 为什么将 T 和 Z 用简单的引号 '' 括起来?我没有(gson 1.7.1)
  • 只是为了给你更多的反馈,我的模式 MM/dd/yy HH:mm:ss SSSZ 给了我这样的日期:02/20/13 18:03:11 089+0100
  • 致克莱门斯,抱歉这么晚才回复。我正在使用 gson 2.2.2。
  • 对于 Samuel,结果字符串是在我无法控制其格式的某个地方生成的。我曾试图删除引号,gson 会抛出一个未知字符异常。我想知道的是,如果毫秒字段存在,则转换行为的区别(一个 ingore 时区而另一个不会)。

标签: java timezone gson


【解决方案1】:

快速解答

第一个字符串使用您的日期格式和您的本地时区正确解析,第二个不尊重它,因此将由没有毫秒的默认 SimpleDateFormat 对象解析(“yyyy-MM-dd'T' HH:mm:ss'Z' 是解析格式)并使用 UTC 时区为您提供时间部分的“偏移”。

完整答案

要全面回答您的问题,您需要深入研究 Gson 源代码。更具体地说,您必须查看用于解析日期的 DefaultDateTypeAdapter 代码。您可以在link 找到所有这些代码,但为了快速参考,我将在此处复制最相关的部分。

当你在构建器中调用它时:

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

您正在以这种方式初始化 DefaultDateTypeAdapter:

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"));
}

地点:

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

因为你已经在构建器中传递了字符串。

注意Locale.US 不是时区,iso8601Format 与enUsFormat 相同,没有毫秒,但有 UTC 时区。

解析发生在deserializeToDate方法中:

 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);
      }
    }
  }

在瀑布方法中使用所有三种日期格式。

第一个 Json 字符串:“2011-11-02T02:50:12.208Z”。它由localFormat 立即解析,因为有毫秒,并为您提供使用您的时区所期望的结果。

第二个 Json 字符串:“1899-12-31T16:00:00Z”。 localFormat 不会解析它,因为它没有毫秒,所以第二次机会是 enUsFormat,它是 相同的模式,除了语言环境。所以它会以同样的方式失败。

解析的最后机会:iso8601Format,它会,它没有毫秒,BUT,用于构造,它也是一个UTC时区,所以它会将日期解析为UTC而其他使用您的时区解析。

【讨论】:

    猜你喜欢
    • 2012-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多