GSON - Formato de fecha

187

Estoy tratando de tener un formato de fecha personalizado en la salida de Gson, pero .setDateFormat(DateFormat.FULL)no parece funcionar y es lo mismo con .registerTypeAdapter(Date.class, new DateSerializer()).

Es como si a Gson no le importara el objeto "Fecha" y lo imprime a su manera.

¿Cómo puedo cambiar eso?

Gracias

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

Yo siempre uso java.util.Date; setDateFormat()no funciona :(

Stéphane Piette
fuente
¿Ha verificado que está importando la clase de fecha correcta en todos los lugares? También el código de ejemplo sería útil.
ML
¿Qué quieres decir con que no funciona? ¿Qué ves realmente?
AlikElzin-kilaka

Respuestas:

306

Parece que necesita definir formatos para la parte de fecha y hora o utilizar el formato basado en cadenas. Por ejemplo:

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

o usando java.text.DateFormat

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

o hacerlo con serializadores:

Creo que los formateadores no pueden producir marcas de tiempo, pero este par serializador / deserializador 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();

Si usa Java 8 o superior, debe usar los serializadores / deserializadores anteriores de la siguiente manera:

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
fuente
Ok, funciona mejor a tu manera. Pero, ¿cómo puedo mostrar marcas de tiempo con esto?
Stéphane Piette
66
Estoy usando Gson 2.2.4 y Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();funciona.
Ramsharan
usando Gson 2.2.2 y Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();funciona
user2601995
66
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();

El formato anterior me parece mejor ya que tiene una precisión de hasta milis.

tj-recess
fuente
1
@Abhi - ¿Por qué es necesario citar 'Z'?
tj-recess
1
Lo intenté sin comillas y gson arrojó la excepción de que la fecha no se puede analizar. ¿Funciona para ti sin comillas?
Abhi
77
Esta NO es la solución correcta ... la Z significa zona horaria y representa la zona horaria UTC, si la codifica así perderá esa información
Billda
5

Como ML señaló, JsonSerializer funciona aquí. Sin embargo, si está formateando entidades de base de datos, use java.sql.Date para registrar su serializador. El deserializador no es necesario.

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

Este informe de error puede estar relacionado: http://code.google.com/p/google-gson/issues/detail?id=230 . Aunque uso la versión 1.7.2.

Milanka
fuente
4

En caso de que odie las clases internas, aprovechando la interfaz funcional puede escribir menos código en Java 8 con una expresión lambda.

JsonDeserializer<Date> dateJsonDeserializer = 
     (json, typeOfT, context) -> json == null ? null : new Date(json.getAsLong());
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class,dateJsonDeserializer).create();
Karthik
fuente
Parece que se puede omitir la verificación nula (Gson lo hace por sí mismo):Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, (JsonDeserializer) (json, typeOfT, context) -> new Date(json.getAsLong())).create();
gmk57
0

Esto realmente no funcionará en absoluto. No hay tipo de fecha en JSON. Recomendaría serializar a ISO8601 de un lado a otro (para agnósticos de formato y compatibilidad JS). Tenga en cuenta que debe saber qué campos contienen fechas.

Michael-O
fuente
0

Puede especificar su formato Gson gson = builder.setDateFormat("yyyy-MM-dd").create(); en este método en lugar de yyyy-MM-ddusar cualquier otro formato

 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
fuente
0

Se trata de un error . Actualmente, también debe establecer un timeStyleo utilizar una de las alternativas descritas en las otras respuestas.

Marcono1234
fuente
0

Estoy en Gson 2.8.6 y descubrí este error hoy.

Mi enfoque permite que todos nuestros clientes existentes (móvil / web / etc.) continúen funcionando como estaban, pero agrega un poco de manejo para aquellos que usan formatos de 24 horas y también permite millis, en buena 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();

Mantuve la serialización igual que todos los clientes entienden el formato estándar de fecha json.

Por lo general, no creo que sea una buena práctica usar bloques try / catch, pero este debería ser un caso bastante raro.

Joe Ciaramitaro
fuente