Spécification d'un format DateTime personnalisé lors de la sérialisation avec Json.Net

137

Je développe une API pour exposer certaines données à l'aide de l'API Web ASP.NET.

Dans l'une des API, le client veut que nous exposions la date au yyyy-MM-ddformat. Je ne veux pas changer les paramètres globaux (par exemple GlobalConfiguration.Configuration.Formatters.JsonFormatter) pour cela car il est très spécifique à ce client. Et je développe cela dans une solution pour plusieurs clients.

Une des solutions à laquelle je pourrais penser est de créer une personnalisation JsonConverter, puis de la placer dans la propriété dont j'ai besoin pour effectuer la mise en forme personnalisée

par exemple

class ReturnObjectA 
{
    [JsonConverter(typeof(CustomDateTimeConverter))]
    public DateTime ReturnDate { get;set;}
}

Je me demande simplement s'il existe un autre moyen facile de le faire.

Restez idiot
la source
16
Pour ce que cela vaut, les API sont destinées à la lisibilité de l'ordinateur, pas à la lisibilité de l'utilisateur, il est donc préférable de s'en tenir à un seul format de date spécifié, tel que ISO 8601 . Si le client affiche directement le résultat de l'API à l'utilisateur ou écrit son propre code d'analyse de date pour l'API, il le fait mal. Le formatage d'une date pour l'affichage doit être laissé à la couche d'interface utilisateur supérieure.
MCattle
Créer une API Web à l'aide de Visual Studio 2019, corrigé par la mise en forme de DateTime dans ASP.NET Core 3.0 à l'aide de System.Text.Json
Stephen

Réponses:

162

Tu es sur la bonne piste. Puisque vous avez dit que vous ne pouvez pas modifier les paramètres globaux, alors la meilleure chose à faire est d'appliquer l' JsonConverterattribut au besoin, comme vous l'avez suggéré. Il s'avère que Json.Net a déjà un intégré IsoDateTimeConverterqui vous permet de spécifier le format de date. Malheureusement, vous ne pouvez pas définir le format via l' JsonConverterattribut, car le seul argument de l'attribut est un type. Cependant, il y a une solution simple: sous - classe la IsoDateTimeConverter, puis spécifiez le format de date dans le constructeur de la sous - classe. Appliquez l' JsonConverterattribut si nécessaire, en spécifiant votre convertisseur personnalisé, et vous êtes prêt à partir. Voici l'intégralité du code nécessaire:

class CustomDateTimeConverter : IsoDateTimeConverter
{
    public CustomDateTimeConverter()
    {
        base.DateTimeFormat = "yyyy-MM-dd";
    }
}

Si cela ne vous dérange pas d'avoir le temps là-dedans également, vous n'avez même pas besoin de sous-classer IsoDateTimeConverter. Son format de date par défaut est yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK(comme indiqué dans le code source ).

Brian Rogers
la source
1
@Koen Zomers - Les guillemets simples que vous avez supprimés de mes formats de date SONT techniquement corrects, bien qu'ils ne soient pas strictement nécessaires ici. Voir Délimiteurs de chaîne littérale dans la documentation des chaînes de format de date et d'heure personnalisées . Cependant, le format que j'ai cité comme format par défaut pour le a IsonDateTimeConverterété tiré directement du code source Json.Net ; donc je reviens sur votre modification à ce sujet.
Brian Rogers
cela n'a pas fonctionné ici avec les citations et il l'a fait sans eux, mais si vous dites que cela devrait, j'ai probablement fait quelque chose de mal. Désolé pour la modification.
Koen Zomers
96

Vous pouvez utiliser cette approche:

public class DateFormatConverter : IsoDateTimeConverter
{
    public DateFormatConverter(string format)
    {
        DateTimeFormat = format;
    }
}

Et utilisez-le de cette façon:

class ReturnObjectA 
{
    [JsonConverter(typeof(DateFormatConverter), "yyyy-MM-dd")]
    public DateTime ReturnDate { get;set;}
}

La chaîne DateTimeFormat utilise la syntaxe de chaîne de format .NET décrite ici: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings

Keith Hill
la source
5
Cela ne fonctionne pas pour moi - je reçois'JsonConverterAttribute' does not contain a constructor that takes 2 arguments
Tam Coton
1
C'est la solution la plus flexible. Si vous obtenez l'erreur suivante 'JsonConverterAttribute' does not contain a constructor that takes 2 arguments:, cela signifie que votre version de json.net est trop ancienne. Vous devez mettre à jour vers la dernière version de json.net.
Florian Lavorel
Travaille pour moi. Une idée comment je peux supprimer le temps? Donc, ne renvoyez que le 12/02/2020 par exemple avec le T00: 00: 00
Enrico
53

Cela peut également être fait avec une IsoDateTimeConverterinstance, sans modifier les paramètres de formatage globaux:

string json = JsonConvert.SerializeObject(yourObject,
    new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });

Cela utilise la JsonConvert.SerializeObjectsurcharge qui prend un params JsonConverter[]argument.

Saeb Amini
la source
5
Si vous sérialisez le même objet de classe à de nombreux endroits, la réponse acceptée est meilleure que celle-ci
kgzdev
16

Également disponible en utilisant l'une des surcharges de paramètres du sérialiseur:

var json = JsonConvert.SerializeObject(someObject, new JsonSerializerSettings() { DateFormatString = "yyyy-MM-ddThh:mm:ssZ" });

Ou

var json = JsonConvert.SerializeObject(someObject, Formatting.Indented, new JsonSerializerSettings() { DateFormatString = "yyyy-MM-ddThh:mm:ssZ" });

Des surcharges prenant un type sont également disponibles.

Mat
la source
2
FYI je pense que vous voulez dire yyyy-MM-ddTHH:mm:ssZ.. 24 heures sur les heures.
Neek
9

Créez une classe d'assistance et appliquez-la à votre attribut de propriété

Classe d'assistance:

public class ESDateTimeConverter : IsoDateTimeConverter
{
    public ESDateTimeConverter()
    {
        base.DateTimeFormat = "yyyy-MM-ddTHH:mm:ss.fffZ";
    }
}

Votre code utilise comme ceci:

[JsonConverter(typeof(ESDateTimeConverter))]
public DateTime timestamp { get; set; }
Xin
la source
8
Pourquoi venez-vous de réitérer ce que plusieurs autres personnes ont déjà déclaré?
Liam
3

Il existe une autre solution que j'utilise. Créez simplement une propriété de chaîne et utilisez-la pour json. Cette propriété retournera la date correctement formatée.

class JSonModel {
    ...

    [JsonProperty("date")]
    public string MyDate { get; set; }

    public string CustomDate {
        get { return MyDate.ToString("DDMMYY"); }
        set { MyDate = DateTime.Parse(value); }
    }

    ...
}

De cette façon, vous n'avez pas à créer de classes supplémentaires. En outre, il vous permet de créer différents formats de données. par exemple, vous pouvez facilement créer une autre propriété pour l'heure en utilisant le même DateTime.

Antonio Rodríguez
la source
0

Parfois, la décoration de l'attribut json convert ne fonctionnera pas, cela fonctionnera grâce à une exception disant que " 2010-10-01" est une date valide . Pour éviter ce type, j'ai supprimé l'attribut json convert sur la propriété et mentionné dans la méthode deserilizedObject comme ci-dessous.

var addresss = JsonConvert.DeserializeObject<AddressHistory>(address, new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd" });
Muni Chittem
la source
0

Avec ci-dessous convertisseur

public class CustomDateTimeConverter : IsoDateTimeConverter
    {
        public CustomDateTimeConverter()
        {
            DateTimeFormat = "yyyy-MM-dd";
        }

        public CustomDateTimeConverter(string format)
        {
            DateTimeFormat = format;
        }
    }

Peut l'utiliser avec un format personnalisé par défaut

class ReturnObjectA 
{
    [JsonConverter(typeof(DateFormatConverter))]
    public DateTime ReturnDate { get;set;}
}

Ou tout format spécifié pour une propriété

class ReturnObjectB 
{
    [JsonConverter(typeof(DateFormatConverter), "dd MMM yy")]
    public DateTime ReturnDate { get;set;}
}
Ranga
la source