将字符串日期转换为对象会产生无效的时区指示符“0”
Convert String date to Object yields Invalid time zone indicator '0'
我有一个 Android 应用程序,它接收来自网络服务的 Json 响应。其中一个响应是 json 字符串,其中包含日期。我以“1476399300000”之类的数字形式获取日期。当我尝试使用 GSON
创建一个对象时,出现此错误:
Failed to parse date ["1476399300000']: Invalid time zone indicator '0' (at offset 0)
双方正在合作java.util.Date
我该如何解决这个问题?
值 1476399300000
看起来像从 Unix epoch 开始的 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());
}
}
配置您的 Gson 实例:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, getUnixEpochDateTypeAdapter())
.create();
Gson
实例是 thread-safe 以及 UnixEpochDateTypeAdapter
是,并且可以作为一个实例全局存在。示例:
final class Mapping {
final Date date = null;
}
final String json = "{\"date\":1476399300000}";
final Mapping mapping = gson.fromJson(json, Mapping.class);
System.out.println(mapping.date);
System.out.println(gson.toJson(mapping));
将给出以下输出:
Fri Oct 14 01:55:00 EEST 2016
{"date":1476399300000}
请注意,类型适配器配置为覆盖默认的 Gson 日期类型适配器。因此,您可能需要使用更复杂的分析来检测 是否只是 Unix 纪元的 ms。另请注意,您可以使用 JsonDeserializer
,但后者以 JSON-tree 方式工作,而类型适配器以流方式工作,这种方式效率更高,可能不会累积中间结果。
编辑:
此外,它可能看起来令人困惑,但 Gson 可以对基元进行值转换。尽管您的负载有一个字符串值,JsonReader.nextLong()
可以将字符串基元读取为长值。所以 UnixEpochDateTypeAdapter.write
应该是 out.value(String.valueOf(value.getTime()));
为了不修改 JSON 文字。
编辑
还有一个更短的解决方案(使用 JSON in-memory 树而不是数据流),它很简单:
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();
我有一个 Android 应用程序,它接收来自网络服务的 Json 响应。其中一个响应是 json 字符串,其中包含日期。我以“1476399300000”之类的数字形式获取日期。当我尝试使用 GSON
创建一个对象时,出现此错误:
Failed to parse date ["1476399300000']: Invalid time zone indicator '0' (at offset 0)
双方正在合作java.util.Date
我该如何解决这个问题?
值 1476399300000
看起来像从 Unix epoch 开始的 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());
}
}
配置您的 Gson 实例:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, getUnixEpochDateTypeAdapter())
.create();
Gson
实例是 thread-safe 以及 UnixEpochDateTypeAdapter
是,并且可以作为一个实例全局存在。示例:
final class Mapping {
final Date date = null;
}
final String json = "{\"date\":1476399300000}";
final Mapping mapping = gson.fromJson(json, Mapping.class);
System.out.println(mapping.date);
System.out.println(gson.toJson(mapping));
将给出以下输出:
Fri Oct 14 01:55:00 EEST 2016
{"date":1476399300000}
请注意,类型适配器配置为覆盖默认的 Gson 日期类型适配器。因此,您可能需要使用更复杂的分析来检测 是否只是 Unix 纪元的 ms。另请注意,您可以使用 JsonDeserializer
,但后者以 JSON-tree 方式工作,而类型适配器以流方式工作,这种方式效率更高,可能不会累积中间结果。
编辑:
此外,它可能看起来令人困惑,但 Gson 可以对基元进行值转换。尽管您的负载有一个字符串值,JsonReader.nextLong()
可以将字符串基元读取为长值。所以 UnixEpochDateTypeAdapter.write
应该是 out.value(String.valueOf(value.getTime()));
为了不修改 JSON 文字。
编辑
还有一个更短的解决方案(使用 JSON in-memory 树而不是数据流),它很简单:
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();