Menentukan format DateTime kustom saat membuat serial dengan Json.Net

143

Saya mengembangkan API untuk mengekspos beberapa data menggunakan ASP.NET Web API.

Di salah satu API, klien ingin kami menampilkan tanggal dalam yyyy-MM-ddformat. Saya tidak ingin mengubah pengaturan global (misalnya GlobalConfiguration.Configuration.Formatters.JsonFormatter) untuk itu karena sangat spesifik untuk klien ini. Dan saya mengembangkannya dalam solusi untuk banyak klien.

Salah satu solusi yang dapat saya pikirkan adalah membuat kustom JsonConverterdan kemudian memasukkannya ke properti yang saya perlukan untuk melakukan pemformatan kustom.

misalnya

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

Hanya ingin tahu apakah ada cara mudah lain untuk melakukan itu.

Tetap Bodoh
sumber
17
Untuk apa nilainya, API adalah untuk keterbacaan komputer, bukan pembacaan pengguna, jadi lebih baik tetap menggunakan satu format tanggal yang ditentukan, seperti ISO 8601 . Jika klien secara langsung menampilkan hasil API kepada pengguna, atau menulis kode parsing tanggal mereka sendiri untuk API, berarti mereka salah melakukannya. Memformat tanggal untuk tampilan harus diserahkan ke lapisan UI paling atas.
MCattle
Buat API web dengan menggunakan Visual Studio 2019, diperbaiki dengan memformat DateTime di ASP.NET Core 3.0 menggunakan System.Text.Json
Stephen

Jawaban:

167

Anda berada di jalur yang benar. Karena Anda mengatakan Anda tidak dapat mengubah pengaturan global, maka hal terbaik berikutnya adalah menerapkan JsonConverteratribut sesuai kebutuhan, seperti yang Anda sarankan. Ternyata Json.Net sudah memiliki built-in IsoDateTimeConverteryang memungkinkan Anda menentukan format tanggal. Sayangnya, Anda tidak dapat menyetel format melalui JsonConverteratribut, karena satu-satunya argumen atribut adalah tipe. Namun, ada solusi sederhana: subclass the IsoDateTimeConverter, lalu tentukan format tanggal di konstruktor subclass tersebut. Terapkan JsonConverteratribut jika diperlukan, tentukan konverter khusus Anda, dan Anda siap untuk pergi. Berikut ini keseluruhan kode yang dibutuhkan:

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

Jika Anda tidak keberatan memiliki waktu di sana juga, Anda bahkan tidak perlu membuat subclass IsoDateTimeConverter. Format tanggal defaultnya adalah yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK(seperti yang terlihat di kode sumber ).

Brian Rogers
sumber
1
@Koen Zomers - Kutipan tunggal yang Anda hapus dari format tanggal saya secara teknis BENAR, meskipun tidak sepenuhnya diperlukan di sini. Lihat Pembatas String Literal dalam dokumentasi untuk String Format Tanggal dan Waktu Kustom . Namun, format yang saya kutip sebagai format default untuk IsonDateTimeConverterdiambil langsung dari kode sumber Json.Net ; oleh karena itu saya mengembalikan hasil edit Anda tentang itu.
Brian Rogers
tidak berfungsi di sini dengan tanda kutip dan tanpa tanda kutip, tetapi jika Anda mengatakan seharusnya, saya mungkin melakukan sesuatu yang salah. Maaf untuk hasil editnya.
Koen Zomers
100

Anda bisa menggunakan pendekatan ini:

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

Dan gunakan dengan cara ini:

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

String DateTimeFormat menggunakan sintaks string format .NET yang dijelaskan di sini: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings

Keith Hill
sumber
5
Ini tidak berhasil untuk saya - saya mengerti'JsonConverterAttribute' does not contain a constructor that takes 2 arguments
Tam Coton
1
Ini adalah solusi paling fleksibel. Jika Anda mendapatkan error berikut 'JsonConverterAttribute' does not contain a constructor that takes 2 arguments:, artinya versi json.net Anda terlalu lama. Anda perlu memperbarui ke versi json.net terbaru.
Florian Lavorel
1
Bekerja untuk saya. Ada ide bagaimana saya bisa menghapus waktu? Jadi hanya kembalikan 2020-02-12 misalnya dengan T00: 00: 00
Enrico
56

Itu juga dapat dilakukan dengan sebuah IsoDateTimeConverterinstance, tanpa mengubah pengaturan pemformatan global:

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

Ini menggunakan JsonConvert.SerializeObjectkelebihan beban yang membutuhkan params JsonConverter[]argumen.

Saeb Amini
sumber
6
Jika Anda membuat serial objek kelas yang sama di banyak tempat, maka jawaban yang diterima lebih baik dari ini
kgzdev
18

Juga tersedia menggunakan salah satu kelebihan pengaturan serializer:

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

Atau

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

Overload mengambil Type juga tersedia.

Matt
sumber
3
FYI, saya pikir maksud Anda yyyy-MM-ddTHH:mm:ssZ.. 24 jam setiap jam.
Neek
11

Buat kelas pembantu dan terapkan ke atribut properti Anda

Kelas pembantu:

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

Kode Anda menggunakan seperti ini:

[JsonConverter(typeof(ESDateTimeConverter))]
public DateTime timestamp { get; set; }
Xin
sumber
10
Mengapa Anda mengulangi apa yang telah dikatakan beberapa orang lain?
Liam
4

Ada solusi lain yang telah saya gunakan. Buat saja properti string dan gunakan untuk json. Properti ini akan mengembalikan tanggal diformat dengan benar.

class JSonModel {
    ...

    [JsonIgnore]
    public DateTime MyDate { get; set; }

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

    ...
}

Dengan cara ini Anda tidak perlu membuat kelas tambahan. Selain itu, ini memungkinkan Anda membuat format data yang berbeda. misalnya, Anda dapat dengan mudah membuat Properti lain untuk Jam menggunakan DateTime yang sama.

Antonio Rodríguez
sumber
0

Beberapa kali mendekorasi atribut json convert tidak akan berfungsi, itu akan melalui pengecualian yang mengatakan bahwa " 2010-10-01" adalah tanggal yang valid . Untuk menghindari tipe ini saya menghapus atribut convert json pada properti dan disebutkan dalam metode deserilizedObject seperti di bawah ini.

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

Dengan konverter di bawah ini

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

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

Dapat menggunakannya dengan format kustom default

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

Atau format tertentu untuk sebuah properti

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