Specifica di un formato DateTime personalizzato durante la serializzazione con Json.Net


137

Sto sviluppando un'API per esporre alcuni dati utilizzando l'API Web ASP.NET.

In una delle API, il cliente vuole che noi esponiamo la data nel yyyy-MM-ddformato. Non voglio cambiare le impostazioni globali (ad es. GlobalConfiguration.Configuration.Formatters.JsonFormatter) Per quello poiché è molto specifico per questo client. E lo faccio sviluppandolo in una soluzione per più clienti.

Una delle soluzioni che mi è venuta in mente è quella di creare un'abitudine JsonConvertere quindi inserirla nella proprietà di cui ho bisogno per eseguire la formattazione personalizzata

per esempio

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

Mi chiedo solo se esiste un altro modo semplice per farlo.


16
Per quello che vale, le API sono per la leggibilità del computer, non per la leggibilità dell'utente, quindi è meglio attenersi a un singolo formato di data specificato, come ISO 8601 . Se il client visualizza direttamente il risultato dell'API per l'utente o sta scrivendo il proprio codice di analisi della data per l'API, lo sta facendo in modo sbagliato. La formattazione di una data per la visualizzazione deve essere lasciata al livello dell'interfaccia utente più in alto.
MCattle,

Crea l'API Web utilizzando Visual Studio 2019, risolto formattando DateTime in ASP.NET Core 3.0 utilizzando System.Text.Json
Stephen

Risposte:


162

Sei sulla strada giusta. Dato che hai detto che non puoi modificare le impostazioni globali, la prossima cosa migliore è applicare l' JsonConverterattributo secondo necessità, come hai suggerito. Si scopre che Json.Net ha già un built-in IsoDateTimeConverterche ti consente di specificare il formato della data. Sfortunatamente, non è possibile impostare il formato tramite l' JsonConverterattributo, poiché l'unico argomento dell'attributo è un tipo. Tuttavia, esiste una soluzione semplice: sottoclasse il IsoDateTimeConverter, quindi specificare il formato della data nel costruttore della sottoclasse. Applica l' JsonConverterattributo dove necessario, specificando il tuo convertitore personalizzato e sei pronto per partire. Ecco l'intero codice necessario:

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

Se non ti dispiace avere anche del tempo lì dentro, non hai nemmeno bisogno di sottoclassare IsoDateTimeConverter. Il formato data predefinito è yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK(come si vede nel codice sorgente ).


1
@Koen Zomers - Le singole virgolette rimosse dai miei formati di data sono tecnicamente corrette, anche se qui non sono strettamente necessarie. Vedere Delimitatori di stringa letterali nella documentazione per Stringhe di formato di data e ora personalizzate . Tuttavia, il formato che ho citato come formato predefinito per il è IsonDateTimeConverterstato preso direttamente dal codice sorgente Json.Net ; quindi sto ripristinando la tua modifica su questo.
Brian Rogers,

non ha funzionato qui con le virgolette e ha fatto senza di loro, ma se dici che dovrebbe, probabilmente ho fatto qualcosa di sbagliato. Ci scusiamo per la modifica.
Koen Zomers,

96

È possibile utilizzare questo approccio:

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

E usalo in questo modo:

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

La stringa DateTimeFormat utilizza la sintassi della stringa in formato .NET qui descritta: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings


5
Questo non funziona per me - capisco'JsonConverterAttribute' does not contain a constructor that takes 2 arguments
Tam Coton l'

1
Questa è la soluzione più flessibile. Se viene visualizzato il seguente errore: 'JsonConverterAttribute' does not contain a constructor that takes 2 argumentssignifica che la versione di json.net è troppo vecchia. Devi aggiornare all'ultima versione di json.net.
Florian Lavorel,

Per me va bene. Qualche idea su come posso rimuovere il tempo? Quindi torna solo il 2020-02-12 ad esempio con il T00: 00: 00
Enrico

53

Può anche essere fatto con IsoDateTimeConverterun'istanza, senza modificare le impostazioni di formattazione globale:

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

Questo utilizza il JsonConvert.SerializeObjectsovraccarico che accetta un params JsonConverter[]argomento.


5
Se stai serializzando lo stesso oggetto di classe in molti posti, la risposta accettata è meglio di questa
kgzdev

16

Disponibile anche utilizzando uno dei sovraccarichi delle impostazioni del serializzatore:

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

O

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

Sono inoltre disponibili sovraccarichi che accettano un tipo.


2
Cordiali saluti, penso che intendi yyyy-MM-ddTHH:mm:ssZ.. 24 ore su 24.
Neek,

9

Crea classe helper e applicala all'attributo della tua proprietà

Classe di aiuto:

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

Il tuo codice usa così:

[JsonConverter(typeof(ESDateTimeConverter))]
public DateTime timestamp { get; set; }

8
Perché hai appena ripetuto ciò che molte altre persone hanno già affermato?
Liam,

3

C'è un'altra soluzione che sto usando. Basta creare una proprietà stringa e usarla per json. Questa proprietà restituirà la data di ritorno formattata correttamente.

class JSonModel {
    ...

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

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

    ...
}

In questo modo non è necessario creare lezioni extra. Inoltre, consente di creare diversi formati di dati. ad esempio, puoi facilmente creare un'altra proprietà per Hour utilizzando lo stesso DateTime.


0

Alcune volte la decorazione dell'attributo json convert non funzionerà, a causa dell'eccezione, dicendo che " 01-10-2010" è una data valida . Per evitare questo tipo, ho rimosso l'attributo json convert dalla proprietà e menzionato nel metodo deserilizedObject come di seguito.

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

0

Con sotto il convertitore

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

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

Può usarlo con un formato personalizzato predefinito

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

O qualsiasi formato specificato per una proprietà

class ReturnObjectB 
{
    [JsonConverter(typeof(DateFormatConverter), "dd MMM yy")]
    public DateTime ReturnDate { get;set;}
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.