如何修复使用Jackson / Gson库解析的不准确的DateTime(分钟)?

时间:2014-11-13 12:43:37

标签: android google-app-engine jackson gson

我正在开发一个与某些Google App Engine网络服务对话的Android应用程序。

此应用程序实现了一个聊天活动,它具有非常简单的功能:发送文本

在调试期间,我注意到我从服务器列出的消息没有按照我在应用程序上发送的顺序显示。我的第一个想法是问题来自服务器。

起初我检查了我收到的原始Json:

{
 "messages": [
  {
   "message": "test 3",
   "author": "daniel",
   "message_id": "5724160613416960",
   "sent_at": "2014-11-13T09:42:42.861950"
  },
  {
   "message": "test 2",
   "author": "daniel",
   "message_id": "5649050225344512",
   "sent_at": "2014-11-13T09:42:10.390960"
  },
  {
   "message": "test 1",
   "author": "daniel",
   "message_id": "5178081291534336",
   "sent_at": "2014-11-13T09:41:01.998830"
  }
 ],
 "kind": "company#chatsItem",
 "etag": "\"RUCkC9XynEQNZ2t5E0aa41edXro/xRNtgkWIUbq4zCgmv2iq2fy-UIg\""
}

如您所见,原始数据已正确排序。但这里有趣的部分。当我添加JSON解析器时,例如JacksonFactory(甚至是GsonFactory):

Company.Builder builder = new Company.Builder(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), null);
Company service = builder.build();
ChatsChatCollectionResponse response = service.chats().list(user_id, album_id, token).execute();
List<ChatsChatResponse> messagesResponse = response.getMessages();

以下是以与上述相同的方式订购的ChatsChatResponse项目:

[0] = {com.appspot.com_pany.company.model.ChatsChatResponse@830029063096} size = 4
[0] = {com.google.api.client.util.DataMap$Entry@830029082528}"author" -> "daniel"
[1] = {com.google.api.client.util.DataMap$Entry@830029082552}"message" -> "test 3"
[2] = {com.google.api.client.util.DataMap$Entry@830029082576}"message_id" -> "5724160613416960"
[3] = {com.google.api.client.util.DataMap$Entry@830029082600}"sent_at" -> "2014-11-13T10:57:03.950+01:00"

[1] = {com.appspot.com_pany.company.model.ChatsChatResponse@830029066376} size = 4
[0] = {com.google.api.client.util.DataMap$Entry@830029083616}"author" -> "daniel"
[1] = {com.google.api.client.util.DataMap$Entry@830029083640}"message" -> "test 2"
[2] = {com.google.api.client.util.DataMap$Entry@830029083664}"message_id" -> "5649050225344512"
[3] = {com.google.api.client.util.DataMap$Entry@830029083688}"sent_at" -> "2014-11-13T10:48:40.960+01:00"

[2] = {com.appspot.com_pany.company.model.ChatsChatResponse@830029068008} size = 4
[0] = {com.google.api.client.util.DataMap$Entry@830029084760}"author" -> "daniel"
[1] = {com.google.api.client.util.DataMap$Entry@830029084784}"message" -> "test 1"
[2] = {com.google.api.client.util.DataMap$Entry@830029084808}"message_id" -> "5178081291534336"
[3] = {com.google.api.client.util.DataMap$Entry@830029084832}"sent_at" -> "2014-11-13T10:57:39.830+01:00"

为什么“sent_at”字段会出现这样的随机差异?

修改 我忘了提到我不是在谈论与TimeZone相对应的1小时班次,而是关于会议记录的随机性。

3 个答案:

答案 0 :(得分:3)

我不确定解决方案,但解释似乎很清楚:变化根本不是随机的,而是在添加所有后引起的小数点,以毫秒为单位。

取第三个条目,例如:

2014-11-13T09:41:01.998830

显然,解析器将其读作:

hours: 09
minutes: 41
seconds: 01
milliseconds: 998830

由于毫秒大于1000,它最终会转换为998s 830ms,当计算完整的分钟数为16m 38s 830ms时。因此:

hours: 09
minutes: 41 + 16
seconds: 01 + 38
milliseconds: 830

这恰好产生了您所看到的结果(模数时区调整):

2014-11-13T10:57:39.830+01:00

如果您可以控制服务输出(这一点在问题措辞中并不十分清楚),最简单的解决方法是在小数点后仅输出三位数(即以毫秒而不是百万分之一舍入)。例如,这将是2014-11-13T09:41:01.999

也许有可能在解析器本身上解决这个问题,但是需要更多的研究(理想情况下,还有一个能够重现问题的要点)。

答案 1 :(得分:1)

尝试设置自定义日期格式,如

  

Gson gson = new   GsonBuilder()setDateFormat(&#34; YYYY-MM-DD&#39; T&#39; HH:MM:SS.SSS&#34)。创建();

答案 2 :(得分:0)

正如@matiash所说,你有一个包含微秒的非标准日期格式。问题是杰克逊使用的SimpleDateFormat incorrectly parses microseconds

为了缓解这个问题,您应该创建一个自定义反序列化器,将微秒截断为毫秒:

public class MicrosecondDateSerializer extends JsonDeserializer<Date> {

  private static SimpleDateFormat formatter = 
    new SimpleDateFormat("dd-MM-yyyyThh:mm:ss:SSS");

  @Override
  public Date deserialize(JsonParser jp, DeserializationContext ctxt)
        throws IOException, JsonProcessingException {

    ObjectCodec oc = jp.getCodec();
    JsonNode node = jp.getCodec().readTree(jp);
    String dateString = node.get("sent_at").asText();
    String dateStringTruncated = dateString.substring(0, dateString.length() - 3);

    return formatter.parse(dateStringTruncated);
  }
}