将GSON序列化日期从json字符串改为java.util.date

jpo*_*s18 74 java android json gson retrofit

我正在使用Retrofit库进行REST调用.我所做的大部分工作都很顺利,但出于某种原因,我遇到了将JSON时间戳字符串转换为java.util.Date对象的问题.进入的JSON看起来像这样.

{
    "date": "2013-07-16",
    "created_at": "2013-07-16T22:52:36Z",
} 
Run Code Online (Sandbox Code Playgroud)

如何告诉Retrofit或Gson将这些字符串转换成java.util.Date objects

gde*_*aco 143

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

RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint(API_BASE_URL)
    .setConverter(new GsonConverter.create(gson))
    .build();
Run Code Online (Sandbox Code Playgroud)

或Kotlin等价物:

val gson = GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create()
RestAdapter restAdapter = Retrofit.Builder()
    .baseUrl(API_BASE_URL)
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()
    .create(T::class.java)
Run Code Online (Sandbox Code Playgroud)

您可以将自定义Gson解析器设置为改装.更多信息:改造网站

看看Ondreju的回应,看看如何在改造中实现这一点2.

  • 请简要解释一下您的代码,以便它对OP和其他读者更有用. (7认同)
  • 这实际上不适用于我的语言环境.`2016-02-11T13:42:14.401Z`被反序列化为一个日期对象,在我的语言环境中为`13:42:14`. (4认同)
  • 为什么没有在“setDateFormat”字符串的末尾包含时区的“Z”参数?我在这里浪费了 2 个小时才发现我应该使用 '"yyyy-MM-dd'T'HH:mm:ss'Z'" 代替。 (2认同)

Ond*_*eju 77

@gderaco的答案更新到改造2.0:

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

Retrofit retrofitAdapter = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
Run Code Online (Sandbox Code Playgroud)

  • 复制日期格式时请注意引号 - 我有问题! (2认同)

Kua*_*kov 12

我是这样做的:

创建DateTime类扩展Date,然后编写自定义反序列化器:

public class DateTime extends java.util.Date {

    public DateTime(long readLong) {
        super(readLong);
    }

    public DateTime(Date date) {
        super(date.getTime());
    }       
}
Run Code Online (Sandbox Code Playgroud)

现在,对于我们注册Date和DateTime转换器的反序列化器部分:

public static Gson gsonWithDate(){
    final GsonBuilder builder = new GsonBuilder();

    builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {  

        final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");  
        @Override  
        public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {  
            try {  
                return df.parse(json.getAsString());  
            } catch (final java.text.ParseException e) {  
                e.printStackTrace();  
                return null;  
            }  
        }
    });

    builder.registerTypeAdapter(DateTime.class, new JsonDeserializer<DateTime>() {  

        final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        @Override  
        public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {  
            try {  
                return new DateTime(df.parse(json.getAsString()));  
            } catch (final java.text.ParseException e) {
                e.printStackTrace();  
                return null;  
            }  
        }
    });

    return builder.create();
}
Run Code Online (Sandbox Code Playgroud)

在创建RestAdapter时,请执行以下操作:

new RestAdapter.Builder().setConverter(gsonWithDate());
Run Code Online (Sandbox Code Playgroud)

你的Foo应该是这样的:

class Foo {
    Date date;
    DateTime created_at;
}
Run Code Online (Sandbox Code Playgroud)


gia*_*olo 7

如果无法使用自定义格式进行解析,Gson只能处理一种日期时间格式(构建器中指定的格式)和iso8601.因此,解决方案可能是编写自定义反序列化程序.为了解决你的问题,我定义了:

package stackoverflow.questions.q18473011;

import java.util.Date;

public class Foo {

    Date date;
    Date created_at;

    public Foo(Date date, Date created_at){
       this.date = date;
       this.created_at = created_at;
    }

    @Override
    public String toString() {
       return "Foo [date=" + date + ", created_at=" + created_at + "]";
    }

}
Run Code Online (Sandbox Code Playgroud)

使用这个反序列化器:

package stackoverflow.questions.q18473011;

import java.lang.reflect.Type;
import java.text.*;
import java.util.Date;

import com.google.gson.*;

public class FooDeserializer implements JsonDeserializer<Foo> {

     public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        String a = json.getAsJsonObject().get("date").getAsString();
        String b = json.getAsJsonObject().get("created_at").getAsString();

        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdfDateWithTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

        Date date, created;
        try {
           date = sdfDate.parse(a);
           created = sdfDateWithTime.parse(b);
        } catch (ParseException e) {
           throw new RuntimeException(e);
        }

        return new Foo(date, created);
    }

}
Run Code Online (Sandbox Code Playgroud)

最后一步是Gson使用正确的适配器创建一个实例:

package stackoverflow.questions.q18473011;

import com.google.gson.*;

public class Question {

    /**
     * @param args
     */
    public static void main(String[] args) {
      String s = "{ \"date\": \"2013-07-16\",    \"created_at\": \"2013-07-16T22:52:36Z\"}";


      GsonBuilder builder = new GsonBuilder();
      builder.registerTypeAdapter(Foo.class, new FooDeserializer());

      Gson gson = builder.create();
      Foo myObject = gson.fromJson(s, Foo.class);

      System.out.println("Result: "+myObject);
    }

}
Run Code Online (Sandbox Code Playgroud)

我的结果:

Result: Foo [date=Tue Jul 16 00:00:00 CEST 2013, created_at=Tue Jul 16 22:52:36 CEST 2013]
Run Code Online (Sandbox Code Playgroud)

  • 如果我在 Foo 中有 15-20 个字段(包括自定义对象),我必须手动反序列化它们,对吗?那么这就破坏了 Gson 的目的。 (2认同)