将JSON日期时间值转换为零值的最佳方法(例如“0000-00-00 00:00:00”)
问题描述:
只将JSON日期时间值转换为零(例如“0000-00-00 00:00:00”)不能使用标准的Json.net IsoDateTimeConverter。我开发了一个保存此值DateTime.MinValue的自定义转换器。另外一个DateTime.MinValue将被写为“ZeroDateString”。所有其他字符串都由基本IsoDateTimeConverter类处理。 我使用此转换器JsonNet注释日期时间属性。将JSON日期时间值转换为零值的最佳方法(例如“0000-00-00 00:00:00”)
有没有更好,更简单的方法来处理这个问题,例如在基础层面上,哪里不需要注释?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace DataLayer
{
/// <summary>
/// Custom IsoDateTimeConverter for DateTime strings with zeros.
///
/// Usage Sample
/// [JsonConverter(typeof(ZerosIsoDateTimeConverter), "yyyy-MM-dd hh:mm:ss", "0000-00-00 00:00:00")]
/// public DateTime Zerodate { get; set; }
/// </summary>
public class ZerosIsoDateTimeConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter
{
/// <summary>
/// The string representing a datetime value with zeros. E.g. "0000-00-00 00:00:00"
/// </summary>
private readonly string _zeroDateString;
/// <summary>
/// Initializes a new instance of the <see cref="ZerosIsoDateTimeConverter"/> class.
/// </summary>
/// <param name="dateTimeFormat">The date time format.</param>
/// <param name="zeroDateString">The zero date string.
/// Please be aware that this string should match the date time format.</param>
public ZerosIsoDateTimeConverter(string dateTimeFormat, string zeroDateString)
{
DateTimeFormat = dateTimeFormat;
_zeroDateString = zeroDateString;
}
/// <summary>
/// Writes the JSON representation of the object.
/// If a DateTime value is DateTime.MinValue than the zeroDateString will be set as output value.
/// </summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is DateTime && (DateTime) value == DateTime.MinValue)
{
value = _zeroDateString;
serializer.Serialize(writer, value);
}
else
{
base.WriteJson(writer, value, serializer);
}
}
/// <summary>
/// Reads the JSON representation of the object.
/// If an input value is same a zeroDateString than DateTime.MinValue will be set as return value
/// </summary>
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader" /> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>
/// The object value.
/// </returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
return reader.Value.ToString() == _zeroDateString
? DateTime.MinValue
: base.ReadJson(reader, objectType, existingValue, serializer);
}
}
}
答
你可以做到这一点使用ContractResolver
如文档中解释说:
的IContractResolver接口提供了一种方式来定制JsonSerializer如何序列化和反序列化.NET对象,以JSON而不将属性上你的类。 任何可以在对象,集合,属性等上使用属性或方法来控制序列化的设置也可以使用IContractResolver进行设置。
http://james.newtonking.com/json/help/index.html?topic=html/ContractResolver.htm
例子:
using System;
using System.Windows.Forms;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private string json = @"
{
""Date"": ""0000-00-00 00:00:00""
}
";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var myClass = new MyClass();
var deserializeObject = JsonConvert.DeserializeObject<MyClass>(json,
new JsonSerializerSettings {ContractResolver = new CustomDateContractResolver()});
string serializeObject = JsonConvert.SerializeObject(myClass, Formatting.Indented,
new JsonSerializerSettings {ContractResolver = new CustomDateContractResolver()});
}
}
internal class MyClass
{
public DateTime DateTime { get; set; }
}
internal class CustomDateContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
JsonContract contract = base.CreateContract(objectType);
bool b = objectType == typeof (DateTime);
if (b)
{
contract.Converter = new ZerosIsoDateTimeConverter("yyyy-MM-dd hh:mm:ss", "0000-00-00 00:00:00");
}
return contract;
}
}
}
但作为@Jeroen Mostert指出,你应该只使用 '常规' 行为可能还没有遇到之后会遇到麻烦,并且无论您使用日期,都必须遵循此自定义逻辑。
为什么不简单地在你的JSON中允许空值并且使用'DateTime?',而不是用哨兵值来弥补? .NET的“零日期”是0001-01-01,SQL Server不允许1753-01-01之前的日期,这个东西很快就会变得混乱。 – 2014-12-05 14:35:42
将这些值存储为可以为空的DateTime值可能是更好的方法。这可能容易实施。但我仍然需要处理传入的“0000 ...”JSON值 – 2014-12-05 20:22:24
使用示例注释中的日期格式应该可能将小时指定为24小时格式:“yyyy-MM-dd HH:mm:ss” 'yyyy-MM-dd hh:mm:ss'。 – bounav 2017-01-15 23:18:29