Angeben eines benutzerdefinierten DateTime-Formats bei der Serialisierung mit Json.Net

137

Ich entwickle eine API, um einige Daten mithilfe der ASP.NET-Web-API verfügbar zu machen.

In einer der APIs möchte der Client, dass wir das Datum im yyyy-MM-ddFormat verfügbar machen. Ich möchte die globalen Einstellungen (z. B. GlobalConfiguration.Configuration.Formatters.JsonFormatter) dafür nicht ändern , da sie für diesen Client sehr spezifisch sind. Und das entwickle ich in einer Lösung für mehrere Kunden.

Eine der Lösungen, an die ich denken könnte, besteht darin, eine benutzerdefinierte zu erstellen JsonConverterund diese dann in die Eigenschaft einzufügen, die ich für die benutzerdefinierte Formatierung benötige

z.B

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

Ich frage mich nur, ob es einen anderen einfachen Weg gibt, dies zu tun.

Bleib dumm
quelle
16
APIs dienen der Computerlesbarkeit und nicht der Benutzerlesbarkeit. Daher ist es besser, sich an ein bestimmtes Datumsformat wie ISO 8601 zu halten . Wenn der Client dem Benutzer das API-Ergebnis direkt anzeigt oder seinen eigenen Datumsanalysecode für die API schreibt, macht er es falsch. Das Formatieren eines Datums für die Anzeige sollte der obersten UI-Ebene überlassen bleiben.
MCattle
Erstellen Sie eine Web-API mit Visual Studio 2019, das durch Formatieren von DateTime in ASP.NET Core 3.0 mit System.Text.Json
Stephen

Antworten:

162

Du bist auf dem richtigen Weg. Da Sie sagten, dass Sie die globalen Einstellungen nicht ändern können, ist es am besten, das JsonConverterAttribut nach Bedarf anzuwenden , wie Sie vorgeschlagen haben. Es stellt sich heraus, dass Json.Net bereits über eine integrierte Funktion verfügt IsoDateTimeConverter, mit der Sie das Datumsformat festlegen können. Leider können Sie das Format nicht über das JsonConverterAttribut festlegen , da das einzige Argument des Attributs ein Typ ist. Es gibt jedoch eine einfache Lösung: Unterklasse die IsoDateTimeConverter, dann geben Sie das Datumsformat im Konstruktor der Unterklasse an. Wenden Sie das JsonConverterAttribut bei Bedarf an und geben Sie Ihren benutzerdefinierten Konverter an. Hier ist der gesamte benötigte Code:

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

Wenn es Ihnen nichts ausmacht, auch dort Zeit zu haben, müssen Sie den IsoDateTimeConverter nicht einmal in Unterklassen unterteilen. Das Standard-Datumsformat ist yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK(wie im Quellcode zu sehen ).

Brian Rogers
quelle
1
@Koen Zomers - Die einfachen Anführungszeichen, die Sie aus meinen Datumsformaten entfernt haben, sind technisch korrekt, obwohl sie hier nicht unbedingt erforderlich sind. Siehe Literale Zeichenfolgenbegrenzer in der Dokumentation für benutzerdefinierte Zeichenfolgen im Datums- und Zeitformat . Das Format, das ich als Standardformat für angegeben habe, IsonDateTimeConverterwurde jedoch direkt aus dem Json.Net-Quellcode übernommen . Deshalb werde ich Ihre Bearbeitung darauf zurücksetzen.
Brian Rogers
Es hat hier mit den Zitaten nicht funktioniert und es hat ohne sie funktioniert, aber wenn Sie sagen, dass es sollte, habe ich wahrscheinlich etwas falsch gemacht. Entschuldigung für die Bearbeitung.
Koen Zomers
96

Sie könnten diesen Ansatz verwenden:

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

Und benutze es so:

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

Die DateTimeFormat-Zeichenfolge verwendet die hier beschriebene Zeichenfolgensyntax im .NET-Format: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings

Keith Hill
quelle
5
Das funktioniert nicht für mich - ich verstehe'JsonConverterAttribute' does not contain a constructor that takes 2 arguments
Tam Coton
1
Dies ist die flexibelste Lösung. Wenn die folgende Fehlermeldung 'JsonConverterAttribute' does not contain a constructor that takes 2 argumentsangezeigt wird, bedeutet dies, dass Ihre Version von json.net zu alt ist. Sie müssen auf die neueste json.net-Version aktualisieren.
Florian Lavorel
Funktioniert bei mir. Irgendeine Idee, wie ich die Zeit entfernen kann? Also nur 2020-02-12 zum Beispiel mit dem T00: 00: 00
Enrico
53

Dies kann auch mit einer IsoDateTimeConverterInstanz erfolgen, ohne die globalen Formatierungseinstellungen zu ändern:

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

Dies verwendet die JsonConvert.SerializeObjectÜberladung, die ein params JsonConverter[]Argument benötigt.

Saeb Amini
quelle
5
Wenn Sie dasselbe Klassenobjekt an vielen Stellen serialisieren, ist die akzeptierte Antwort besser als diese
kgzdev
16

Auch verfügbar mit einer der Überladungen der Serializer-Einstellungen:

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

Oder

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

Überladungen, die einen Typ annehmen, sind ebenfalls verfügbar.

Matt
quelle
2
Zu Ihrer Information, ich denke du meinst yyyy-MM-ddTHH:mm:ssZ... 24 Stunden im Uhrzeigersinn.
Neek
9

Erstellen Sie eine Hilfsklasse und wenden Sie sie auf Ihr Eigenschaftsattribut an

Hilfsklasse:

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

Ihr Code verwendet wie folgt:

[JsonConverter(typeof(ESDateTimeConverter))]
public DateTime timestamp { get; set; }
Xin
quelle
8
Warum haben Sie gerade wiederholt, was einige andere bereits gesagt haben?
Liam
3

Es gibt eine andere Lösung, die ich verwendet habe. Erstellen Sie einfach eine Zeichenfolgeeigenschaft und verwenden Sie sie für json. Diese Eigenschaft wird das Datum korrekt formatiert zurückgeben.

class JSonModel {
    ...

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

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

    ...
}

Auf diese Weise müssen Sie keine zusätzlichen Klassen erstellen. Außerdem können Sie verschiedene Datenformate erstellen. Sie können beispielsweise ganz einfach eine andere Eigenschaft für die Stunde mit derselben DateTime erstellen.

Antonio Rodríguez
quelle
0

Manchmal funktioniert das Dekorieren des json convert-Attributs nicht. Ausnahmsweise wird angegeben, dass " 2010-10-01" ein gültiges Datum ist . Um diese Typen zu vermeiden, habe ich das json convert-Attribut für die Eigenschaft entfernt und in der deserilizedObject-Methode wie unten erwähnt erwähnt.

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

Mit unterem Konverter

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

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

Kann mit einem benutzerdefinierten Standardformat verwendet werden

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

Oder ein bestimmtes Format für eine Eigenschaft

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