Chỉ định định dạng DateTime tùy chỉnh khi tuần tự hóa với Json.Net


137

Tôi đang phát triển API để hiển thị một số dữ liệu bằng API Web ASP.NET.

Trong một trong các API, khách hàng muốn chúng tôi hiển thị ngày ở yyyy-MM-ddđịnh dạng. Tôi không muốn thay đổi cài đặt toàn cầu (ví dụ GlobalConfiguration.Configuration.Formatters.JsonFormatter) vì điều đó rất cụ thể đối với khách hàng này. Và tôi phát triển điều đó trong một giải pháp cho nhiều khách hàng.

Một trong những giải pháp mà tôi có thể nghĩ đến là tạo một tùy chỉnh JsonConvertervà sau đó đặt nó vào thuộc tính tôi cần để thực hiện định dạng tùy chỉnh

ví dụ

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

Chỉ tự hỏi nếu có một số cách dễ dàng khác để làm điều đó.


16
Đối với giá trị của nó, API dành cho khả năng đọc trên máy tính, không phải khả năng đọc của người dùng, vì vậy tốt hơn hết là bạn nên giữ một định dạng ngày được chỉ định, chẳng hạn như ISO 8601 . Nếu khách hàng đang trực tiếp hiển thị kết quả API cho người dùng hoặc viết mã phân tích ngày của riêng họ cho API, thì họ đã làm sai. Định dạng một ngày để hiển thị phải được để lại cho lớp UI trên cùng.
MCattle

Tạo API web bằng cách sử dụng Visual Studio 2019, được sửa bằng Định dạng DateTime trong ASP.NET Core 3.0 bằng System.Text.Json
Stephen

Câu trả lời:


162

Bạn đang đi đúng hướng. Vì bạn nói rằng bạn không thể sửa đổi cài đặt chung, nên điều tốt nhất tiếp theo là áp dụng JsonConverterthuộc tính trên cơ sở khi cần, như bạn đã đề xuất. Hóa ra Json.Net đã tích hợp sẵn IsoDateTimeConvertercho phép bạn chỉ định định dạng ngày. Thật không may, bạn không thể đặt định dạng thông qua JsonConverterthuộc tính, vì đối số duy nhất của thuộc tính là một loại. Tuy nhiên, có một giải pháp đơn giản: phân lớp IsoDateTimeConverter, sau đó chỉ định định dạng ngày trong hàm tạo của lớp con. Áp dụng JsonConverterthuộc tính khi cần, chỉ định trình chuyển đổi tùy chỉnh của bạn và bạn đã sẵn sàng để đi. Đây là toàn bộ mã cần thiết:

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

Nếu bạn không có thời gian ở đó, bạn thậm chí không cần phải phân lớp IsoDateTimeConverter. Định dạng ngày mặc định của nó là yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK(như được thấy trong mã nguồn ).


1
@Koen Zomers - Các trích dẫn duy nhất bạn đã xóa khỏi định dạng ngày của tôi về mặt kỹ thuật là chính xác, mặc dù chúng không thực sự cần thiết ở đây. Xem Dấu phân cách chuỗi ký tự trong tài liệu về Chuỗi định dạng ngày và giờ tùy chỉnh . Tuy nhiên, định dạng tôi trích dẫn là định dạng mặc định cho IsonDateTimeConverterđược lấy trực tiếp từ mã nguồn Json.Net ; do đó tôi hoàn nguyên chỉnh sửa của bạn về điều đó.
Brian Rogers

nó không hoạt động ở đây với các trích dẫn và nó đã làm mà không có chúng, nhưng nếu bạn nói nó nên, tôi có lẽ đã làm gì đó sai. Xin lỗi vì đã chỉnh sửa.
Koen Zomers

96

Bạn có thể sử dụng phương pháp này:

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

Và sử dụng nó theo cách này:

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

Chuỗi DateTimeFormat sử dụng cú pháp chuỗi định dạng .NET được mô tả ở đây: https://docs.microsoft.com/en-us/dotnet/stiteria/base-types/custom-date-and-time-format-strings


5
Điều này không hiệu quả với tôi - tôi hiểu'JsonConverterAttribute' does not contain a constructor that takes 2 arguments
Tam Coton

1
Đây là giải pháp linh hoạt nhất. Nếu bạn gặp lỗi sau 'JsonConverterAttribute' does not contain a constructor that takes 2 arguments:, điều đó có nghĩa là phiên bản json.net của bạn đã quá cũ. Bạn cần cập nhật lên phiên bản json.net mới nhất.
Florian Lavorel

Làm việc cho tôi. Bất cứ ý tưởng làm thế nào tôi có thể loại bỏ thời gian? Vì vậy, chỉ trả lại 2020-02-12 chẳng hạn với T00: 00: 00
Enrico

53

Nó cũng có thể được thực hiện với một IsoDateTimeConverterthể hiện, mà không thay đổi cài đặt định dạng toàn cầu:

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

Điều này sử dụng JsonConvert.SerializeObjectquá tải mà có một params JsonConverter[]đối số.


5
Nếu bạn đang tuần tự hóa cùng một đối tượng lớp ở nhiều nơi, thì câu trả lời được chấp nhận sẽ tốt hơn thế này
kgzdev

16

Cũng có sẵn bằng cách sử dụng một trong các cài đặt serializer quá tải:

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

Hoặc là

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

Quá tải lấy một loại cũng có sẵn.


2
FYI tôi nghĩ bạn có nghĩa là yyyy-MM-ddTHH:mm:ssZ.. đồng hồ 24 giờ vào giờ.
Neek

9

Xây dựng lớp trình trợ giúp và áp dụng nó vào thuộc tính thuộc tính của bạn

Lớp người trợ giúp:

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

Mã của bạn sử dụng như thế này:

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

8
Tại sao bạn vừa lặp lại những gì một số người khác đã nêu?
Liam

3

Có một giải pháp khác mà tôi đang sử dụng. Chỉ cần tạo một thuộc tính chuỗi và sử dụng nó cho json. Khách sạn này sẽ trả lại ngày được định dạng đúng.

class JSonModel {
    ...

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

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

    ...
}

Bằng cách này, bạn không phải tạo thêm lớp. Ngoài ra, nó cho phép bạn tạo các định dạng dữ liệu khác nhau. ví dụ: bạn có thể dễ dàng tạo một Thuộc tính khác cho Giờ bằng cùng một DateTime.


0

Đôi khi trang trí thuộc tính json convert sẽ không hoạt động, thông qua ngoại lệ nói rằng " 2010-10-01" là ngày hợp lệ . Để tránh loại này, tôi đã loại bỏ thuộc tính json convert trên thuộc tính và được đề cập trong phương thức deserilizedObject như bên dưới.

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

0

Với bộ chuyển đổi dưới đây

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

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

Có thể sử dụng nó với định dạng tùy chỉnh mặc định

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

Hoặc bất kỳ định dạng được chỉ định cho một tài sản

class ReturnObjectB 
{
    [JsonConverter(typeof(DateFormatConverter), "dd MMM yy")]
    public DateTime ReturnDate { get;set;}
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.