使用 Json.Net 序列化时指定自定义 DateTime 格式

Posted

技术标签:

【中文标题】使用 Json.Net 序列化时指定自定义 DateTime 格式【英文标题】:Specifying a custom DateTime format when serializing with Json.Net 【发布时间】:2013-09-09 05:52:43 【问题描述】:

我正在开发一个 API 来使用 ASP.NET Web API 公开一些数据。

在其中一个 API 中,客户端希望我们以 yyyy-MM-dd 格式公开日期。我不想为此更改全局设置(例如GlobalConfiguration.Configuration.Formatters.JsonFormatter),因为它非常特定于该客户端。我确实在为多个客户开发解决方案。

我能想到的解决方案之一是创建一个自定义 JsonConverter,然后将其放入我需要进行自定义格式设置的属性

例如

class ReturnObjectA 

    [JsonConverter(typeof(CustomDateTimeConverter))]
    public DateTime ReturnDate  get;set;

只是想知道是否有其他简单的方法可以做到这一点。

【问题讨论】:

对于它的价值,API 是为了计算机可读性,而不是用户可读性,因此最好坚持使用单一指定的日期格式,例如 ISO 8601。如果客户端直接向用户显示 API 结果,或者为 API 编写自己的日期解析代码,那么他们做错了。格式化显示日期应留给最顶层的 UI 层。 使用 Visual Studio 2019 创建 Web API,由Formatting DateTime in ASP.NET Core 3.0 using System.Text.Json修复 我避免在我的 DTO 中添加 Json.NET 细节。相反,我有你提到的 DTO 日期属性为 strings,它们使用共享的 const string 值格式化。 【参考方案1】:

你在正确的轨道上。既然您说您不能修改全局设置,那么接下来最好的做法是按照您的建议根据需要应用 JsonConverter 属性。事实证明 Json.Net 已经有一个内置的IsoDateTimeConverter 可以让你指定日期格式。不幸的是,您不能通过JsonConverter 属性设置格式,因为该属性的唯一参数是一个类型。但是,有一个简单的解决方案:将IsoDateTimeConverter 子类化,然后在子类的构造函数中指定日期格式。在需要的地方应用JsonConverter 属性,指定您的自定义转换器,然后您就可以开始使用了。以下是所需的全部代码:

class CustomDateTimeConverter : IsoDateTimeConverter

    public CustomDateTimeConverter()
    
        base.DateTimeFormat = "yyyy-MM-dd";
    

如果您不介意也有时间,您甚至不需要子类化 IsoDateTimeConverter。它的默认日期格式是yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK(见source code)。

【讨论】:

@Koen Zomers - 你从我的日期格式中删除的单引号在技术上是正确的,尽管在这里它们不是绝对必要的。请参阅documentation for Custom Date and Time Format Strings 中的文字字符串分隔符。但是,我引用的IsonDateTimeConverter 的默认格式直接取自Json.Net source code;因此,我正在恢复您对此的编辑。 这里没有引号,没有引号也可以,但如果你说它应该,我可能做错了什么。抱歉编辑。【参考方案2】:

您可以使用这种方法:

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

【讨论】:

这对我不起作用 - 我得到 'JsonConverterAttribute' does not contain a constructor that takes 2 arguments 这是最灵活的解决方案。如果您收到以下错误:'JsonConverterAttribute' does not contain a constructor that takes 2 arguments,则表示您的 json.net 版本太旧。您需要更新到最新的 json.net 版本。 为我工作。知道如何删除时间吗?所以只返回 2020-02-12 例如 T00:00:00 @Enrico Simple:[JsonConverter(typeof(DateFormatConverter), "yyyy-MM-dd\"T:00:00:00\"")] @TamCoton 看到此错误的原因之一可能是您在文件中引用“System.Text.Json”而不是“Newtonsoft.Json”。至少这是我的问题案例。【参考方案3】:

也可以使用IsoDateTimeConverter 实例来完成,而无需更改全局格式设置:

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

这使用带有params JsonConverter[] 参数的JsonConvert.SerializeObject 重载。

【讨论】:

如果你在很多地方序列化同一个类对象,那么接受的答案比这个更好【参考方案4】:

也可以使用序列化程序设置重载之一:

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" );

采用 Type 的重载也是可用的。

【讨论】:

仅供参考,我认为您的意思是 yyyy-MM-ddTHH:mm:ssZ .. 24 小时制。【参考方案5】:

我一直在使用另一种解决方案。只需创建一个字符串属性并将其用于 json。此属性将返回格式正确的日期。

class JSonModel 
    ...

    [JsonIgnore]
    public DateTime MyDate  get; set; 

    [JsonProperty("date")]
    public string CustomDate 
        get  return MyDate.ToString("ddMMyyyy"); 
        // set  MyDate = DateTime.Parse(value); 
        set  MyDate = DateTime.ParseExact(value, "ddMMyyyy", null); 
    

    ...

这样您就不必创建额外的类。此外,它还允许您创建不同的数据格式。例如,您可以使用相同的 DateTime 轻松创建另一个 Hour 属性。

【讨论】:

【参考方案6】:

带有以下转换器

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

        public CustomDateTimeConverter(string format)
        
            DateTimeFormat = format;
        
    

可以使用默认的自定义格式

class ReturnObjectA 

    [JsonConverter(typeof(CustomDateTimeConverter))]
    public DateTime ReturnDate  get;set;

或任何指定的属性格式

class ReturnObjectB 

    [JsonConverter(typeof(CustomDateTimeConverter), "dd MMM yy")]
    public DateTime ReturnDate  get;set;

【讨论】:

【参考方案7】:
public static JsonSerializerSettings JsonSerializer  get; set;  = new JsonSerializerSettings()
        
            DateFormatString= "yyyy-MM-dd HH:mm:ss",
            NullValueHandling = NullValueHandling.Ignore,
            ContractResolver = new LowercaseContractResolver()
        ;

你好,

我在需要设置 JsonSerializerSettings 时使用此属性

【讨论】:

【参考方案8】:

有时修饰 json 转换属性不起作用,它会通过异常说“2010-10-01”是有效日期。为了避免这种类型,我删除了属性上的 json convert 属性,并在下面的 deserilizedObject 方法中提到。

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

【讨论】:

以上是关于使用 Json.Net 序列化时指定自定义 DateTime 格式的主要内容,如果未能解决你的问题,请参考以下文章

JSON.Net无法在自定义JsonConverter中反序列化json数组

反序列化 Web.API 参数时未调用自定义 Json.NET JsonConverter

使用JSON.NET实现对象属性的自定义化格式

使用 Json.NET 自定义反序列化

ASP.NET MVC 下自定义 JsonResult,使用 Json.NET 序列化 JSON

使用 JSON.NET 反序列化自定义 null 处理