Json.Net ile serileştirirken özel bir DateTime biçimi belirtme


137

ASP.NET Web API kullanarak bazı verileri ortaya çıkarmak için bir API geliştiriyorum.

API'lardan birinde, müşteri tarihi yyyy-MM-ddformatta göstermemizi ister . GlobalConfiguration.Configuration.Formatters.JsonFormatterBu istemciye çok özel olduğu için bunun için genel ayarları (örneğin ) değiştirmek istemiyorum . Ve bunu birden fazla müşteri için bir çözümde geliştiriyorum.

Aklıma gelen bir çözüm, bir özel oluşturmak JsonConverterve daha sonra özel biçimlendirme yapmak için gereken özelliği koymak

Örneğin

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

Bunu yapmanın başka kolay bir yolu olup olmadığını merak etmek.


16
Değerine göre, API'ler kullanıcı tarafından okunabilirlik için değil, bilgisayar tarafından okunabilirlik içindir, bu nedenle ISO 8601 gibi belirtilen tek bir tarih biçimine bağlı kalmak daha iyidir . İstemci doğrudan API sonucunu kullanıcıya gösteriyorsa veya API için kendi tarih ayrıştırma kodunu yazıyorsa, bunu yanlış yapıyor demektir. Görüntüleme için bir tarih biçimlendirmesi en üstteki kullanıcı arayüzü katmanına bırakılmalıdır.
MCattle

Yanıtlar:


162

Doğru yoldasın. Genel ayarları değiştiremeyeceğinizi söylediğinizden, bir sonraki en iyi şey, JsonConverterözniteliği önerdiğiniz gibi gerektiği şekilde uygulamaktır . Görünüşe göre Json.Net IsoDateTimeConverter, tarih biçimini belirlemenizi sağlayan yerleşik bir yapıya sahip . Maalesef, JsonConverterniteliğin tek argümanı bir tür olduğundan formatı özellik üzerinden ayarlayamazsınız . Ancak, basit bir çözüm vardır: alt sınıfı IsoDateTimeConverter, ardından alt sınıfın yapıcısında tarih biçimini belirtin. JsonConverterÖzel dönüştürücünüzü belirterek özelliği gerektiği yerde uygulayın, artık hazırsınız. İşte gerekli kodun tamamı:

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

Orada zaman geçirmenin de bir sakıncası yoksa IsoDateTimeConverter öğesinin alt sınıfını bile almanıza gerek yoktur. Varsayılan tarih biçimi yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK( kaynak kodunda görüldüğü gibi ) şeklindedir.


1
@Koen Zomers - Tarih formatlarımdan kaldırdığınız tek alıntılar teknik olarak doğrudur, ancak burada kesinlikle gerekli değildirler. Özel Tarih ve Saat Biçimi Dizeleri için belgelerdeki Değişmez Dize Sınırlayıcıları konusuna bakın . Ancak, için varsayılan biçim olarak belirtilen biçim doğrudan Json.Net kaynak kodundan alınmıştır ; bu nedenle bu konudaki düzenlemenizi geri alıyorum. IsonDateTimeConverter
Brian Rogers

burada tırnak işaretleri ile işe yaramadı ve onlarsız yaptı, ama eğer söylersen, muhtemelen yanlış bir şey yaptım. Düzenleme için üzgünüm.
Koen Zomers

96

Bu yaklaşımı kullanabilirsiniz:

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

Ve şu şekilde kullanın:

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

DateTimeFormat dizesi, burada açıklanan .NET biçimi dize sözdizimini kullanır: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings


5
Bu benim için çalışmıyor - Anladım'JsonConverterAttribute' does not contain a constructor that takes 2 arguments
Tam Coton

1
Bu en esnek çözümdür. Aşağıdaki hatayı alırsanız: 'JsonConverterAttribute' does not contain a constructor that takes 2 argumentsjson.net sürümünüz çok eski demektir. En son json.net sürümüne güncellemeniz gerekir.
Florian Lavorel

Benim için çalışıyor. Zamanı nasıl kaldırabileceğim hakkında bir fikrin var mı? Bu yüzden sadece 2020-02-12'yi iade edin, örneğin T00: 00: 00
Enrico

53

Genel IsoDateTimeConverterbiçimlendirme ayarlarını değiştirmeden bir örnekle de yapılabilir :

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

Bu, argüman alan JsonConvert.SerializeObjectaşırı yükü kullanır params JsonConverter[].


5
Aynı sınıf nesnesini birçok yerde serileştiriyorsanız, kabul edilen cevap bundan daha iyidir
kgzdev

16

Ayrıca, serileştirici ayarları aşırı yüklerinden birini kullanarak da kullanılabilir:

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

Veya

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

Tip alan aşırı yükler de mevcuttur.


2
FYI Sanırım demek istedin yyyy-MM-ddTHH:mm:ssZ.. 24 saat açık.
Neek

9

Yardımcı sınıf oluşturun ve bunu özellik özelliğinize uygulayın

Yardımcı sınıf:

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

Kodunuz şu şekilde kullanılır:

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

8
Neden daha önce başka birkaç kişinin söylediklerini tekrarladınız?
Liam

3

Kullandığım başka bir çözüm daha var. Bir dize özelliği oluşturun ve bunu json için kullanın. Bu özellik, iade tarihinin düzgün bir şekilde biçimlendirilmesini sağlayacaktır.

class JSonModel {
    ...

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

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

    ...
}

Bu şekilde ekstra sınıflar oluşturmak zorunda kalmazsınız. Ayrıca, farklı veri formatları oluşturmanıza izin verir. ör. aynı DateTime kullanarak kolayca Saat için başka bir Özellik oluşturabilirsiniz.


0

Bazı durumlarda json convert özniteliğini dekore etmek işe yaramaz, istisna olarak " 2010-10-01" geçerli bir tarih olduğunu söyleyecektir . Bu tür önlemek için özellik üzerinde json convert özniteliği kaldırıldı ve aşağıdaki gibi deserilizedObject yönteminde bahsedilen.

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

0

Aşağıdaki dönüştürücü ile

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

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

Varsayılan bir özel formatla kullanabilir

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

Veya bir mülk için belirtilen herhangi bir biçim

class ReturnObjectB 
{
    [JsonConverter(typeof(DateFormatConverter), "dd MMM yy")]
    public DateTime ReturnDate { get;set;}
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.