การระบุรูปแบบ DateTime แบบกำหนดเองเมื่อทำการจัดลำดับด้วย Json.Net


137

ฉันกำลังพัฒนา API เพื่อเปิดเผยข้อมูลบางอย่างโดยใช้ ASP.NET Web API

ในหนึ่งใน API ลูกค้าต้องการให้เราเปิดเผยวันที่ในyyyy-MM-ddรูปแบบ ฉันไม่ต้องการเปลี่ยนการตั้งค่าส่วนกลาง (เช่นGlobalConfiguration.Configuration.Formatters.JsonFormatter) สำหรับสิ่งนั้นเนื่องจากมีความเฉพาะเจาะจงสำหรับลูกค้า และฉันจะพัฒนาสิ่งนั้นในโซลูชันสำหรับลูกค้าหลายราย

หนึ่งในวิธีการแก้ปัญหาที่ฉันคิดได้ก็คือการสร้างกำหนดเองJsonConverterจากนั้นนำไปใช้กับคุณสมบัติที่ฉันต้องใช้ในการจัดรูปแบบที่กำหนดเอง

เช่น

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

แค่สงสัยว่ามีวิธีอื่นที่ง่ายกว่าในการทำเช่นนั้น


16
สำหรับสิ่งที่มันคุ้มค่า API ที่มีเพื่อให้สามารถอ่านคอมพิวเตอร์ไม่สามารถอ่านได้ใช้จึงดีกว่าที่จะยึดติดอยู่กับรูปแบบวันที่ที่ระบุเดียวเช่นISO 8601 หากลูกค้าแสดงผล API โดยตรงให้กับผู้ใช้หรือเขียนรหัสการแยกวิเคราะห์วันที่ของตนเองสำหรับ API แสดงว่าพวกเขาทำผิด การจัดรูปแบบวันที่สำหรับการแสดงผลควรอยู่ในเลเยอร์ UI ระดับบนสุด
MCattle

สร้างเว็บ API โดยใช้ Visual Studio 2019 แก้ไขโดยการจัดรูปแบบ DateTime ใน ASP.NET Core 3.0 โดยใช้ System.Text.Json
Stephen

คำตอบ:


162

คุณอยู่ในเส้นทางที่ถูกต้อง เนื่องจากคุณบอกว่าคุณไม่สามารถแก้ไขการตั้งค่าส่วนกลางดังนั้นสิ่งที่ดีที่สุดถัดไปคือการใช้JsonConverterแอตทริบิวต์ตามความจำเป็นตามที่คุณแนะนำ ปรากฎว่า Json.Net มีอยู่แล้วในตัวIsoDateTimeConverterที่ช่วยให้คุณระบุรูปแบบวันที่ น่าเสียดายที่คุณไม่สามารถตั้งค่ารูปแบบผ่านแอJsonConverterททริบิวเนื่องจากอาร์กิวเมนต์ของแอททริบิวนั้นเป็นประเภท อย่างไรก็ตามมีวิธีแก้ปัญหาง่ายๆคือ: subclass IsoDateTimeConverterจากนั้นระบุรูปแบบวันที่ในนวกรรมิกของคลาสย่อย ใช้JsonConverterคุณลักษณะที่จำเป็นระบุตัวแปลงที่กำหนดเองของคุณและคุณพร้อมที่จะไป นี่คือรหัสทั้งหมดที่จำเป็น:

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

ถ้าคุณไม่รังเกียจที่จะมีเวลาอยู่ในนั้นคุณก็ไม่จำเป็นต้องใช้คลาสย่อยของ IsoDateTimeConverter รูปแบบวันที่เริ่มต้นคือyyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK(ตามที่เห็นในซอร์สโค้ด )


1
@Ken Zomers - คำพูดเดียวที่คุณลบออกจากรูปแบบวันที่ทางเทคนิคของฉันถูกต้องแม้ว่าพวกเขาจะไม่จำเป็นที่นี่ ดูตามตัวอักษรสตริงตัวคั่นในเอกสารสำหรับวันที่กำหนดเองและเวลาสตริงรูปแบบ อย่างไรก็ตามรูปแบบที่ฉันยกมาเป็นรูปแบบเริ่มต้นสำหรับIsonDateTimeConverterถูกนำโดยตรงจากซอร์สโค้ด Json.Net ; ดังนั้นฉันจะคืนค่าการแก้ไขของคุณในสิ่งนั้น
Brian Rogers

มันใช้ไม่ได้กับคำพูดและมันก็ทำโดยไม่มีพวกเขา แต่ถ้าคุณบอกว่ามันควรฉันอาจทำอะไรผิด ขออภัยสำหรับการแก้ไข
Koen Zomers

96

คุณสามารถใช้วิธีนี้:

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

และใช้วิธีนี้:

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

สตริง DateTimeFormat ใช้ไวยากรณ์สตริงรูปแบบ. NET ที่อธิบายไว้ที่นี่: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings


5
สิ่งนี้ใช้ไม่ได้สำหรับฉัน - ฉันได้รับ'JsonConverterAttribute' does not contain a constructor that takes 2 arguments
Tam Coton

1
นี่คือทางออกที่ยืดหยุ่นที่สุด หากคุณได้รับข้อผิดพลาดต่อไปนี้: แสดง'JsonConverterAttribute' does not contain a constructor that takes 2 argumentsว่า json.net รุ่นของคุณเก่าเกินไป คุณต้องอัปเดตเป็น json.net เวอร์ชันล่าสุด
Florian Lavorel

ได้ผลสำหรับฉัน มีความคิดใดที่ฉันจะลบเวลาได้บ้าง ดังนั้นให้ส่งคืน 2020-02-12 เท่านั้นเช่น T00: 00: 00
Enrico

53

มันสามารถทำได้กับIsoDateTimeConverterอินสแตนซ์โดยไม่ต้องเปลี่ยนการตั้งค่าการจัดรูปแบบทั่วโลก:

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

นี่ใช้JsonConvert.SerializeObjectโอเวอร์โหลดที่รับparams JsonConverter[]อาร์กิวเมนต์


5
หากคุณจัดลำดับวัตถุคลาสเดียวกันในหลาย ๆ แห่งคำตอบที่ได้รับการยอมรับจะดีกว่านี้
kgzdev

16

สามารถใช้งานได้โดยใช้การตั้งค่าหนึ่งในการตั้งค่าอนุกรม

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

หรือ

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

นอกจากนี้ยังมีการรับน้ำหนักเกินจำนวนด้วย


2
FYI ฉันคิดว่าคุณหมายถึงyyyy-MM-ddTHH:mm:ssZ.. ตลอด 24 ชั่วโมงในชั่วโมง
Neek

9

สร้างคลาสตัวช่วยและใช้กับคุณสมบัติคุณสมบัติของคุณ

ระดับผู้ช่วย:

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

รหัสของคุณใช้ดังนี้:

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

8
ทำไมคุณถึงซ้ำสิ่งที่คนอื่นหลายคนได้ระบุไว้แล้ว?
เลียม

3

มีวิธีแก้ไขปัญหาอื่นที่ฉันใช้อยู่ เพียงสร้างคุณสมบัติสตริงและใช้สำหรับ json คุณสมบัตินี้จะส่งคืนวันที่ในรูปแบบที่ถูกต้อง

class JSonModel {
    ...

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

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

    ...
}

วิธีนี้คุณไม่ต้องสร้างคลาสเพิ่มเติม นอกจากนี้ยังช่วยให้คุณสามารถสร้างรูปแบบข้อมูลที่แตกต่างกัน เช่นคุณสามารถสร้างคุณสมบัติอื่นสำหรับชั่วโมงโดยใช้ DateTime เดียวกันได้อย่างง่ายดาย


0

บางครั้งการตกแต่ง JSON แปลงแอตทริบิวต์จะไม่ทำงานก็จะผ่านข้อยกเว้นบอกว่า " 2010/10/01" เป็นวันที่ถูกต้อง เพื่อหลีกเลี่ยงประเภทนี้ฉันลบ json คุณสมบัติการแปลงในทรัพย์สินและกล่าวถึงในวิธีการ deserilizedObject เช่นด้านล่าง

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

0

ด้วยตัวแปลงด้านล่าง

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

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

สามารถใช้กับรูปแบบที่กำหนดเองเริ่มต้น

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

หรือรูปแบบที่ระบุสำหรับคุณสมบัติ

class ReturnObjectB 
{
    [JsonConverter(typeof(DateFormatConverter), "dd MMM yy")]
    public DateTime ReturnDate { get;set;}
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.