GSON - Formato da data

187

Estou tentando ter um formato de data personalizado na saída do Gson, mas .setDateFormat(DateFormat.FULL)não parece funcionar e é o mesmo com .registerTypeAdapter(Date.class, new DateSerializer()).

É como se o Gson não se importasse com o objeto "Data" e o imprimisse à sua maneira.

Como posso mudar isso?

obrigado

EDITAR:

@Entity
public class AdviceSheet {
  public Date lastModif;
[...]
}

public void method {
   Gson gson = new GsonBuilder().setDateFormat(DateFormat.LONG).create();
   System.out.println(gson.toJson(adviceSheet);
}

Eu sempre uso java.util.Date; setDateFormat()não funciona :(

Stéphane Piette
fonte
Você verificou se está importando a classe Date correta em todos os lugares? Também exemplo de código seria útil.
ML
O que você quer dizer com não funciona? O que você realmente vê?
AlikElzin-Kilaka

Respostas:

306

Parece que você precisa definir formatos para a parte de data e hora ou usar a formatação baseada em String. Por exemplo:

Gson gson = new GsonBuilder()
   .setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create();

ou usando java.text.DateFormat

Gson gson = new GsonBuilder()
   .setDateFormat(DateFormat.FULL, DateFormat.FULL).create();

ou faça isso com serializadores:

Acredito que os formatadores não podem produzir registros de data e hora, mas esse par serializador / desserializador parece funcionar

JsonSerializer<Date> ser = new JsonSerializer<Date>() {
  @Override
  public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext 
             context) {
    return src == null ? null : new JsonPrimitive(src.getTime());
  }
};

JsonDeserializer<Date> deser = new JsonDeserializer<Date>() {
  @Override
  public Date deserialize(JsonElement json, Type typeOfT,
       JsonDeserializationContext context) throws JsonParseException {
    return json == null ? null : new Date(json.getAsLong());
  }
};

Gson gson = new GsonBuilder()
   .registerTypeAdapter(Date.class, ser)
   .registerTypeAdapter(Date.class, deser).create();

Se estiver usando o Java 8 ou superior, você deve usar os serializadores / desserializadores acima, da seguinte maneira:

JsonSerializer<Date> ser = (src, typeOfSrc, context) -> src == null ? null
            : new JsonPrimitive(src.getTime());

JsonDeserializer<Date> deser = (jSon, typeOfT, context) -> jSon == null ? null : new Date(jSon.getAsLong());
ML
fonte
Ok, funciona melhor com o seu caminho. Mas como posso exibir registros de data e hora com isso?
Stéphane Piette
6
Estou usando o Gson 2.2.4 e Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();funciona.
Ramsharan
usando Gson 2.2.2 e Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();funciona
user2601995 4/04/14
66
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();

O formato acima parece melhor para mim, pois tem precisão de até milis.

recesso tj
fonte
1
@Abhi - Por que é necessário citar 'Z'?
tj-recess
1
Eu tentei sem aspas e gson lançou Exceção de que a data não é analisável. Isso funciona para você sem aspas?
Abhi
7
Esta não é a solução certa .. o Z significa fuso horário e representa o fuso horário UTC, se você codificar dessa maneira, perderá essa informação
Billda 04/04
5

Como ML apontou, o JsonSerializer funciona aqui. No entanto, se você estiver formatando entidades do banco de dados, use java.sql.Date para registrar seu serializador. O desserializador não é necessário.

Gson gson = new GsonBuilder()
   .registerTypeAdapter(java.sql.Date.class, ser).create();

Este relatório de erros pode estar relacionado: http://code.google.com/p/google-gson/issues/detail?id=230 . Eu uso a versão 1.7.2 embora.

Milanka
fonte
4

Caso você odeie classes Inner, aproveitando a interface funcional, você pode escrever menos código no Java 8 com uma expressão lambda.

JsonDeserializer<Date> dateJsonDeserializer = 
     (json, typeOfT, context) -> json == null ? null : new Date(json.getAsLong());
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class,dateJsonDeserializer).create();
Karthik
fonte
Parece que a verificação nula pode ser omitida (o Gson faz isso por si só):Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, (JsonDeserializer) (json, typeOfT, context) -> new Date(json.getAsLong())).create();
gmk57 24/09
0

Isso realmente não vai funcionar. Não há tipo de data no JSON. Eu recomendaria serializar para ISO8601 e para trás (para agnósticos de formato e compatíveis com JS). Considere que você precisa saber quais campos contêm datas.

Michael-O
fonte
0

Você pode especificar o formato Gson gson = builder.setDateFormat("yyyy-MM-dd").create(); neste método, em vez de yyyy-MM-ddusar outros formatos

 GsonBuilder builder = new GsonBuilder();
                        builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
                            public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                                return new Date(json.getAsJsonPrimitive().getAsLong());
                            }
                        });

                        Gson gson = builder.setDateFormat("yyyy-MM-dd").create();
Abhijit Chakra
fonte
0

Isso é um bug . Atualmente, você também precisa definir um timeStyleou usar uma das alternativas descritas nas outras respostas.

Marcono1234
fonte
0

Estou no Gson 2.8.6 e descobri esse bug hoje.

Minha abordagem permite que todos os nossos clientes existentes (móveis / web / etc) continuem funcionando como estavam, mas adiciona um pouco de manipulação para aqueles que usam formatos de 24 horas e permite milis também, por uma boa medida.

Gson rawGson = new Gson();
SimpleDateFormat fmt = new SimpleDateFormat("MMM d, yyyy HH:mm:ss")
private class DateDeserializer implements JsonDeserializer<Date> {
    @Override
    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        try {
            return new rawGson.fromJson(json, Date.class);
        } catch (JsonSyntaxException e) {}
        String timeString = json.getAsString();
        log.warning("Standard date deserialization didn't work:" + timeString);
        try {
            return fmt.parse(timeString);
        } catch (ParseException e) {}
        log.warning("Parsing as json 24 didn't work:" + timeString);
        return new Date(json.getAsLong());
    }
}

Gson gson = new GsonBuilder()
    .registerTypeAdapter(Date.class, new DateDeserializer())
    .create();

Eu mantive a serialização da mesma forma que todos os clientes entendem o formato de data json padrão.

Normalmente, acho que não é uma boa prática usar blocos try / catch, mas esse deve ser um caso bastante raro.

Joe Ciaramitaro
fonte