将字符串日期转换为对象产生无效的时区指示符'0'

Yon*_*Nir 5 java json gson java.util.date

我有一个Android应用程序,它接收来自Web服务的Json响应.其中一个响应是一个内部有日期的json字符串.我以"1476399300000"之类的数字形式获取日期.当我尝试用它创建一个对象GSON我得到这个错误:

无法解析日期["1476399300000"]:无效的时区指示符'0'(偏移0处)

双方正在合作 java.util.Date

我该如何解决这个问题?

Lyu*_*riv 19

1476399300000Unix纪元开始,该值看起来像ms .只需在Gson中添加一个类型适配器:

final class UnixEpochDateTypeAdapter
        extends TypeAdapter<Date> {

    private static final TypeAdapter<Date> unixEpochDateTypeAdapter = new UnixEpochDateTypeAdapter();

    private UnixEpochDateTypeAdapter() {
    }

    static TypeAdapter<Date> getUnixEpochDateTypeAdapter() {
        return unixEpochDateTypeAdapter;
    }

    @Override
    public Date read(final JsonReader in)
            throws IOException {
        // this is where the conversion is performed
        return new Date(in.nextLong());
    }

    @Override
    @SuppressWarnings("resource")
    public void write(final JsonWriter out, final Date value)
            throws IOException {
        // write back if necessary or throw UnsupportedOperationException
        out.value(value.getTime());
    }

}
Run Code Online (Sandbox Code Playgroud)

配置您的Gson实例:

final Gson gson = new GsonBuilder()
        .registerTypeAdapter(Date.class, getUnixEpochDateTypeAdapter())
        .create();
Run Code Online (Sandbox Code Playgroud)

Gson实例UnixEpochDateTypeAdapter既是线程安全的,也是,并且可以作为一个全局实例存在.例:

final class Mapping {   
    final Date date = null; 
}
Run Code Online (Sandbox Code Playgroud)
final String json = "{\"date\":1476399300000}";
final Mapping mapping = gson.fromJson(json, Mapping.class);
System.out.println(mapping.date);
System.out.println(gson.toJson(mapping));
Run Code Online (Sandbox Code Playgroud)

会给出以下输出:

Fri Oct 14 01:55:00 EEST 2016
{"date":1476399300000}

请注意,类型适配器配置为覆盖默认的Gson日期类型适配器.因此,您可能需要使用更复杂的分析来检测是否只是Unix时代的ms.另请注意,您可以使用JsonDeserializer,但后者以JSON树方式工作,而类型适配器以流式方式工作,这种方式更有效,可能不会累积中间结果.

编辑:

此外,它可能看起来令人困惑,但Gson可以为原语进行值转换.尽管您的有效负载具有字符串值,但JsonReader.nextLong()可以将字符串原语读取为长值.所以UnixEpochDateTypeAdapter.write应该是out.value(String.valueOf(value.getTime()));为了不修改JSON文字.

编辑

还有一个更短的解决方案(使用JSON内存树而不是数据流),这简单:

final Gson builder = new GsonBuilder()
    .registerTypeAdapter(Date.class, new JsonDeserializer<Date>() { 
       public Date deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
          return new Date(jsonElement.getAsJsonPrimitive().getAsLong()); 
       } 
    })
    .create();
Run Code Online (Sandbox Code Playgroud)