web-dev-qa-db-fra.com

Comment obtenir JSON.NET pour sérialiser la date / heure à ISO 8601?

J'ai une application Web API qui renvoie JSON aux consommateurs qui n'utilisent peut-être pas les technologies Microsoft. Lorsque mon contrôleur renvoie un objet avec les propriétés DateTime au format JSON, il sérialise la date dans ce format:

2017-03-15T00:00:00-04:00

Cela donne au consommateur un peu de mal de tête car ils s'attendent à ce qu'il soit au format ISO 8601. Certaines recherches m'ont dit que JSON.NET utilise désormais ISO 8601 par défaut (j'utilise 9.0.1). Quand j'exécute ce code ...

Clipboard.Copy(JsonConvert.SerializeObject(DateTime.Now));

...J'ai compris:

2017-03-15T09:10:13.8105498-04:00

Wikipedia les présente comme des formats ISO 8601 valides lors de l'expression de la date et de l'heure complètes:

2017-03-15T11:45:42+00:00
2017-03-15T11:45:42Z
20170315T114542Z

Cependant, la sortie que j'ai obtenue ci-dessus ne correspond exactement à aucun de ceux-ci. Je veux que le formateur utilise 2017-03-15T11:45:42Z.

Et probablement digne d'une autre question, l'ajout de la ligne ci-dessous dans ma configuration d'API Web semble être ignoré car il continue de renvoyer JSON à la date indiquée ci-dessus:

config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter());

Je suppose qu'une fois que j'ai compris le problème principal, le problème de l'API Web peut également être résolu.

18
oscilatingcretin

Le format que vous obtenez est format ISO 8601 (lisez la section sur les désignateurs d'heure et de fuseau horaire dans Wikipedia), c'est juste que vos dates ne sont apparemment pas ajustées à l'heure UTC, donc vous obtenez un décalage de fuseau horaire ajouté à la date plutôt qu'à l'indicateur de fuseau horaire Z Zulu.

IsoDateTimeConverter possède des paramètres que vous pouvez utiliser pour personnaliser sa sortie. Vous pouvez le faire ajuster automatiquement les dates en UTC en définissant DateTimeStyles sur AdjustToUniversal. Vous pouvez également personnaliser le format de sortie pour omettre les fractions de seconde si vous ne les souhaitez pas. Par défaut, le convertisseur ne s'ajuste pas à l'heure UTC et inclut autant de décimales de précision qu'il y en a pour les secondes.

Essaye ça:

IsoDateTimeConverter converter = new IsoDateTimeConverter
{
    DateTimeStyles = DateTimeStyles.AdjustToUniversal,
    DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssK"
};

config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(converter);

Si vos dates sont déjà UTC, mais que le DateTimeKind sur celles-ci n'est pas défini sur Utc comme il devrait l'être (par exemple, c'est Unspecified), alors idéalement, vous devriez corriger votre code afin que cet indicateur soit correctement défini avant la sérialisation. Cependant, si vous ne pouvez pas (ou ne voulez pas) le faire, vous pouvez contourner ce problème en modifiant les paramètres du convertisseur pour toujours inclure l'indicateur Z dans le format de date (au lieu d'utiliser le K spécificateur qui regarde le DateTimeKind à la date) et en supprimant la directive AdjustToUniversal.

IsoDateTimeConverter converter = new IsoDateTimeConverter
{
    DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
};
27
Brian Rogers

Ajout à la réponse de @Brian Rogers, pour ASP Core, ajoutez Startup.cs:

services.AddMvc()
  .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
  .AddJsonOptions(options =>
    options.SerializerSettings.Converters.Add(new IsoDateTimeConverter
    {
      DateTimeStyles = DateTimeStyles.AdjustToUniversal
    }));
2
Assaf S.