web-dev-qa-db-fra.com

Java Date à UTC en utilisant gson

Je n'arrive pas à obtenir gson pour convertir une date en heure UTC en Java .... Voici mon code ...

Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").create();
//This is the format I want, which according to the ISO8601 standard - Z specifies UTC - 'Zulu' time

Date now=new Date();          
System.out.println(now);       
System.out.println(now.getTimezoneOffset());
System.out.println(gson.toJson(now));

Voici ma sortie

Thu Sep 25 18:21:42 BST 2014           // Time now - in British Summer Time 
-60                                    // As expected : offset is 1hour from UTC    
"2014-09-25T18:21:42.026Z"             // Uhhhh this is not UTC ??? Its still BST !!

Le résultat gson que je veux et ce que j'attendais

"2014-09-25T17:21:42.026Z"

Je peux clairement soustraire 1 heure avant l'appel à Json, mais cela semble être un hack. Comment puis-je configurer gson pour toujours convertir en UTC?

35
Marky0

Après quelques recherches supplémentaires, il semble que ce soit un problème connu. Le sérialiseur par défaut de gson est toujours défini par défaut sur votre fuseau horaire local et ne vous permet pas de spécifier le fuseau horaire. Voir le lien suivant .....

https://code.google.com/p/google-gson/issues/detail?id=281

La solution consiste à créer un adaptateur de type gson personnalisé, comme illustré dans le lien:

// this class can't be static
public class GsonUTCDateAdapter implements JsonSerializer<Date>,JsonDeserializer<Date> {

    private final DateFormat dateFormat;

    public GsonUTCDateAdapter() {
      dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);      //This is the format I need
      dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));                               //This is the key line which converts the date to UTC which cannot be accessed with the default serializer
    }

    @Override public synchronized JsonElement serialize(Date date,Type type,JsonSerializationContext jsonSerializationContext) {
        return new JsonPrimitive(dateFormat.format(date));
    }

    @Override public synchronized Date deserialize(JsonElement jsonElement,Type type,JsonDeserializationContext jsonDeserializationContext) {
      try {
        return dateFormat.parse(jsonElement.getAsString());
      } catch (ParseException e) {
        throw new JsonParseException(e);
      }
    }
}

Enregistrez-le ensuite comme suit:

  Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new GsonUTCDateAdapter()).create();
  Date now=new Date();
  System.out.println(gson.toJson(now));

Cela affiche désormais correctement la date en UTC

"2014-09-25T17:21:42.026Z"

Merci à l'auteur du lien.

91
Marky0

La solution qui a fonctionné pour moi pour ce problème était de créer un adaptateur de date personnalisé (faites attention à P.S afin d'importer Java.util.Date ne pas Java.sql.Date!)

public class ColonCompatibileDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer< Date> {
private final DateFormat dateFormat;

public ColonCompatibileDateTypeAdapter() {
  dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") {
        @Override
        public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {
            StringBuffer rfcFormat = super.format(date, toAppendTo, pos);
            return rfcFormat.insert(rfcFormat.length() - 2, ":");
        }

        @Override
        public Date parse(String text, ParsePosition pos) {
            if (text.length() > 3) {
                text = text.substring(0, text.length() - 3) + text.substring(text.length() - 2);
            }
            return super.parse(text, pos);
        }
    };


}

@Override public synchronized JsonElement serialize(Date date, Type type,
    JsonSerializationContext jsonSerializationContext) {
  return new JsonPrimitive(dateFormat.format(date));
}

@Override public synchronized Date deserialize(JsonElement jsonElement, Type type,
    JsonDeserializationContext jsonDeserializationContext) {
  try {
      return dateFormat.parse(jsonElement.getAsString());
  } catch (ParseException e) {
    throw new JsonParseException(e);
  }
}}

puis l'utiliser lors de la création d'un objet GSON

Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new ColonCompatibileDateTypeAdapter()).create();
2
martar

Le Z dans votre format de date est entre guillemets simples, il doit être sans guillemets pour être remplacé par le fuseau horaire réel.

De plus, si vous voulez que votre date soit en UTC, convertissez-la d'abord.

1
sleeplessnerd

J'ai adapté le solution marqué et paramétré le DateFormat:

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import Java.lang.reflect.Type;
import Java.text.DateFormat;
import Java.text.ParseException;
import Java.util.Date;

public class GsonDateFormatAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {

    private final DateFormat dateFormat;

    public GsonDateFormatAdapter(DateFormat dateFormat) {
        this.dateFormat = dateFormat;
    }

    @Override
    public synchronized JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) {
        return new JsonPrimitive(dateFormat.format(date));
    }

    @Override
    public synchronized Date deserialize(JsonElement jsonElement, Type type,JsonDeserializationContext jsonDeserializationContext) {
        try {
            return dateFormat.parse(jsonElement.getAsString());
        } catch (ParseException e) {
            throw new JsonParseException(e);
        }
    }
}
1
Ferran Maylinch