Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将GSON序列化日期从json字符串改为java.util.Date_Java_Android_Json_Gson_Retrofit - Fatal编程技术网

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

将GSON序列化日期从json字符串改为java.util.Date,java,android,json,gson,retrofit,Java,Android,Json,Gson,Retrofit,我正在使用改装库进行REST调用。我所做的大部分工作都很顺利,但由于某些原因,我在将JSON时间戳字符串转换为java.util.Date对象时遇到了问题。即将出现的JSON如下所示 { "date": "2013-07-16", "created_at": "2013-07-16T22:52:36Z", } 如果无法使用自定义格式进行解析,我如何告诉Reformation或Gson将这些字符串转换为java.util.Date对象?Gson只能处理一种日期时间格式(在bui

我正在使用改装库进行REST调用。我所做的大部分工作都很顺利,但由于某些原因,我在将JSON时间戳字符串转换为
java.util.Date
对象时遇到了问题。即将出现的JSON如下所示

{
    "date": "2013-07-16",
    "created_at": "2013-07-16T22:52:36Z",
} 

如果无法使用自定义格式进行解析,我如何告诉Reformation或Gson将这些字符串转换为
java.util.Date对象?

Gson只能处理一种日期时间格式(在builder中指定的格式)和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 + "]";
    }

}
使用此反序列化程序:

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

}
public class DateTime extends java.util.Date {

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

    public DateTime(Date date) {
        super(date.getTime());
    }       
}
public class MyDateDeserializer implements JsonDeserializer<Date> {

    public static final SimpleDateFormat sServerDateDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public MyDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
         if (json != null) {
            final String jsonString = json.getAsString();
            try {
                return (MyDate) sServerDateDateFormat.parse(jsonString);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
我的结果是:

Result: Foo [date=Tue Jul 16 00:00:00 CEST 2013, created_at=Tue Jul 16 22:52:36 CEST 2013]
或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)
您可以将定制的Gson解析器设置为改装。详情如下:

查看OnDerreage的回复,了解如何在改装2中实现这一点。

以下是我如何做到的:

创建扩展日期的DateTime类,然后编写自定义反序列化程序:

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

}
public class DateTime extends java.util.Date {

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

    public DateTime(Date date) {
        super(date.getTime());
    }       
}
public class MyDateDeserializer implements JsonDeserializer<Date> {

    public static final SimpleDateFormat sServerDateDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public MyDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
         if (json != null) {
            final String jsonString = json.getAsString();
            try {
                return (MyDate) sServerDateDateFormat.parse(jsonString);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
现在,对于反序列化器部分,我们在其中注册日期和日期时间转换器:

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();
}
您的Foo应该如下所示:

class Foo {
    Date date;
    DateTime created_at;
}
import java.util.Date;

public class MyDate extends Date {
}
import MyDate;
import CreatedAtDate;

public class Foo {
    MyDate date;
    CreatedAtDate created_at;
}

如果您在创建的类中已经有一个名为“created_at”的日期对象,那么很简单:

Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").create();
YourObject parsedObject1 = gson.fromJson(JsonStringYouGotSomehow, YourObject.class);

你完成了。不需要复杂的重写。

您可以定义如下两个新类:

class Foo {
    Date date;
    DateTime created_at;
}
import java.util.Date;

public class MyDate extends Date {
}
import MyDate;
import CreatedAtDate;

public class Foo {
    MyDate date;
    CreatedAtDate created_at;
}

您的POJO将如下所示:

class Foo {
    Date date;
    DateTime created_at;
}
import java.util.Date;

public class MyDate extends Date {
}
import MyDate;
import CreatedAtDate;

public class Foo {
    MyDate date;
    CreatedAtDate created_at;
}
最后设置自定义反序列化程序:

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

}
public class DateTime extends java.util.Date {

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

    public DateTime(Date date) {
        super(date.getTime());
    }       
}
public class MyDateDeserializer implements JsonDeserializer<Date> {

    public static final SimpleDateFormat sServerDateDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public MyDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
         if (json != null) {
            final String jsonString = json.getAsString();
            try {
                return (MyDate) sServerDateDateFormat.parse(jsonString);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

@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();

这并不能直接回答所问的问题,但在我看来,这是“最先进的”,如果编码者在如何解决问题上有充分的选择自由

首先,使用java.util.Date并不是最好的解决方案。原因是这些类在某些极端情况下没有理想的行为,因此Java Instant类等取代了这些类。请查看Basil Bourque在这个S.O.问题中的答案:

所以我使用了3TENABP的即时类 在Android上使用Kotlin:

val gson = GsonBuilder().registerTypeAdapter(Instant::class.java,
    JsonDeserializer<Instant> { json: JsonElement, _: Type?, _: JsonDeserializationContext? ->
        ZonedDateTime.parse(
            json.asJsonPrimitive.asString
        ).toInstant()
    }
).create()

val retrofit = Retrofit.Builder()
    .baseUrl(baseUrl)
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()
val gson=GsonBuilder().registerTypeAdapter(Instant::class.java,
JsonDeserializer{json:JsonElement,u3;:类型?,3;:JsonDeserializationContext?->
ZoneDateTime.parse(
json.asJsonPrimitive.asString
).toInstant()
}
).create()
val reformation=reformation.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()

看起来像的副本。@Davmrtl:这不一样,因为这里有两种不同的日期格式。因此,它需要一种不同的方法。请简要解释您的代码,以便它对OP和其他读者更有用。我如何才能对所有请求执行此操作?因此,将其添加到我的
ServiceGenerator
?这实际上并不适用于我的语言环境
2016-02-11T13:42:14.401Z
被反序列化为一个日期对象,该对象在我的区域设置中用于
13:42:14
。我已经尝试过了,下载的项目现在似乎可以工作了。但是当我将Json对象发布到服务器时。然后它会删除我的时区吗?在实施此解决方案后,我花了很多时间来检测应用程序无理由崩溃的问题。当我复制并粘贴dete格式时,有东西将引号从“T”改为“T”-有一个不同的-仔细观察!谢谢我只需要从
返回df.parse(json.getAsString())进行更改
to
long timeStamp=long.parseLong(json.getAsString());返回新的java.util.Date(时间戳)太好了!非常感谢。复制日期格式时注意引号-我有问题!如果我在Foo中有15-20个字段(包括自定义对象),我必须手动反序列化它们,对吗。这就扼杀了Gson的用途。你应该在“你完成了。不需要复杂的覆盖”之前,先尝试一下改装。这是行不通的。