web-dev-qa-db-fra.com

Fuseau horaire par défaut pour la désérialisation DateTime avec Jackson (module Joda-Time)

Cette question concerne la désérialisation vers Joda-TimeDateTime à l'aide de module jackson-datatype-joda pour Jackson. Existe-t-il un fuseau horaire par défaut dans lequel les chaînes de date seront désérialisées? Si oui, c'est quoi? Est-ce UTC?

J'ai besoin de poser cette question car la documentation de Jackson n'est pas spécifique à Joda-Time DateTime. J'ai trouvé dans cet article ( http://wiki.fasterxml.com/JacksonFAQDateHandling ) que Jackson assumera GMT comme fuseau horaire par défaut pour la désérialisation en Java.util.Date ou Java.util.Calendar . Cependant, les types de données Joda-Time ne sont pas mentionnés dans ce document. De plus, j'ai particulièrement besoin de chaînes pour désérialiser des objets DateTime à l'aide du fuseau horaire UTC, et non de GMT: bien que ces deux zones soient très similaires, il existe quelques petites différences et que, par conséquent, GMT ne sera pas réalisable. .

Je vous remercie.

16
ecbrodie

Le code source de DateTimeDeserializer indique qu'il utilise le fuseau horaire de DeserializationContext fourni par ObjectMapper lors de la désérialisation. Si vous regardez ObjectMapper API, vous verrez qu'il existe une méthode pour définir le fuseau horaire:

public ObjectMapper setTimeZone(TimeZone tz)

Ainsi, vous pouvez utiliser cette méthode pour configurer votre ObjectMapper et définir le fuseau horaire sur celui qui convient.

En ce qui concerne la valeur par défaut, il semble que la Javadoc dit une chose, mais le code en montre une autre.

Javadoc pour ObjectMapper.setTimeZone(TimeZone tz):

/**
  * Method for overriding default TimeZone to use for formatting.
  * Default value used is {@link TimeZone#getDefault()}.
  */

Cependant, le code définit explicitement le fuseau horaire sur:

protected final static BaseSettings DEFAULT_BASE = new BaseSettings(
    ...
    // TimeZone.getDefault()
    TimeZone.getTimeZone("GMT"),
    ...

Donc, apparemment, il utilise réellement GMT, et non la valeur par défaut de la JVM.

Je dirais que le meilleur choix serait probablement de ne pas compter sur cela et de le régler vous-même sur ObjectMapper.setTimeZone(TimeZone tz).

22
Redder

UTC versus GMT

Pour les applications professionnelles, il n'y a pas de différence pratique entre UTC et GMT . La seule différence concerne la résolution inférieure à la seconde et un saut de seconde ajouté tous les plusieurs années. Pour la science, l'astronomie, le suivi par satellite et de telles applications, la différence peut être importante, mais c'est rare.

Jackson par défaut à UTC/GMT

Je ne sais pas Jackson. Mais si vous regardez le document que vous avez lié, il semble qu’ils sérialisent (a) le nombre de millisecondes depuis le 1er janvier 1970, UTC ou (b) un format de chaîne, le format par défaut étant ISO 8601 format: " 1970-01-01T00: 00: 00.000 + 0000 ". Donc, pour répondre à votre question sur les fuseaux horaires, il semble que par défaut, Jackson se sérialise toujours en utilisant le temps UTC (sans décalage de fuseau horaire), ce qui est la bonne façon de le faire. Si vous vous souciez du fuseau horaire utilisé à ce moment-là, vous devez enregistrer ce fait (quel fuseau horaire) dans un champ séparé.

Jackson ↔ Java.util.Date/Calendar ↔ Joda-Time

Ces deux valeurs sérialisées (millisecondes et chaîne ISO 8601) peuvent être utilisées avec les constructeurs pour Joda-Time DateTime instances.

String dateTimeString = "2013-11-22T18:37:55.645+0000";
org.joda.time.DateTime myDateTime = org.joda.time.format.ISODateTimeFormat.dateTime().withZoneUTC().parseDateTime( dateTimeString );

et…

Long millisSinceEpoch = 1385495462L;
org.joda.time.DateTime myDateTime = new org.joda.time.DateTime( millisSinceEpoch );

Si vous n'avez pas d'accès direct à ces valeurs sérialisées pour alimenter les constructeurs Joda-Time DateTime, laissez Jackson instancier les objets Java.util.Date/Calendar. Chargez ces objets Java.util.Date/Calendar dans Joda-Time pour instancier des objets DateTime en vue d'un travail ultérieur. Les utilisateurs de Joda-Time le font couramment.

org.joda.time.DateTime myDateTime = new org.joda.time.DateTime( someJavaUtilDateFromJackson );

Vous pouvez facilement convertir cette heure UTC en d'autres fuseaux horaires dans Joda-Time en appelant la méthode toDateTime () et en transmettant le fuseau horaire souhaité.

org.joda.time.DateTimeZone kolkataTimeZone = org.joda.time.DateTimeZone.forID( "Asia/Kolkata" );
org.joda.time.DateTime dateTimeInKolkata = myDateTime.toDateTime( kolkataTimeZone ); 

Joda-Time est facilement reconverti en Java.util.Date à l’aide de la méthode toDate . Faites donc la plupart de votre travail dans Joda-Time et reconvertissez-le en Java.util.Date pour communiquer avec Jackson. Et lorsque je revenais à Jackson, je revenais à l'heure UTC pour une bonne mesure.

myDateTime.toDateTime( org.joda.time.DateTimeZone.UTC )

Vous trouverez de nombreux exemples des opérations Joda-Time susmentionnées ici sur StackOverflow.com.

Simplement fais-le

Je suppose que vous faites un peu trop d’inquiétude et pas assez de codage. Essayez juste quelques expériences en passant des valeurs de Jackson et Joda-Time. Vous allez vite comprendre. Je vous recommande de laisser Jackson faire ce qu'il veut par défaut, puis de le manipuler dans Joda-Time. Joda-Time est conçu pour les problèmes épineux de date-heure, et Jackson ne l’est probablement pas. Joda-Time a à la fois des constructeurs et des méthodes pour ajuster les fuseaux horaires comme vous le souhaitez.

Un avenir meilleur

En Java 8, JSR 310: API de date et heure apporte des classes de type Joda-Time intégrées à la plate-forme Java. Attendez-vous à voir des infrastructures telles que Jackson mises à jour pour fonctionner directement avec ces nouvelles classes tout en rendant obsolète les classes laides Java.util.Date/Calendar.

Il semble que/ le projet jackson-datatype-joda tente de vous apporter ce genre de commodité maintenant pour Joda-Time. Mais cela ne me semble pas nécessaire. Vous pouvez simplement convertir Java.util.Date/Calendar et Joda-Time comme indiqué ci-dessus.

P.S. Le lien "Wiki" pour la documentation de ce projet échoue. Je ne pouvais donc pas regarder leur doc.

17
Basil Bourque

J'ai également eu du mal avec les formats de date et j'ai finalement trouvé une solution. Je voulais utiliser le format "2016-02-08T12:49:22.876Z" puisqu'il s'agit de l'ISO 8601 et qu'il est utilisé par JavaScript Date object. Je voulais aussi toujours utiliser le fuseau horaire UTC. 

J'ai trouvé que cela peut être fait en utilisant le code suivant:

final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(dateFormat);

System.out.println(objectMapper.writeValueAsString(new Date()));

Veuillez noter le caractère X dans la chaîne de format. Il est pris en charge à partir de Java 7 et spécifie le fuseau horaire dans ISO 8601. Comme indiqué dans le document SimpleDateFormat , il génère Z (au lieu de +00:00) si le décalage de fuseau horaire est 0 (UTC).

3
Vojta

À partir d’un simple code, j’ai trouvé que, lorsque Jackson désérialise l’objet Date à partir de chaîne, il indique UTC si aucun fuseau horaire n’est mentionné, mais qu’il est instancié directement, donne le fuseau horaire par défaut i.e., le fuseau horaire de la machine.

DateTime date = new DateTime(2013, 1, 2, 0, 0) //gives local timezone

Après donne UTC

ObjectMapper mapper = new ObjectMapper();
DateTime dt = new DateTime(2013, 1, 2, 0, 0);
String serialized = mapper.writeValueAsString(dt);
DateTime dt1 = mapper.readValue(serialized, DateTime.class); //gives UTC
1
Neil