【问题标题】:Best way to convert JSON DateTime values with Zero values (e.g. "0000-00-00 00:00:00")用零值转换 JSON DateTime 值的最佳方法(例如“0000-00-00 00:00:00”)
【发布时间】:2015-02-03 16:52:07
【问题描述】:

仅使用零转换 JSON 日期时间值(例如“0000-00-00 00:00:00”)不适用于标准 Json.net IsoDateTimeConverter。我开发了一个自定义转换器来保存这个值 DateTime.MinValue。 DateTime.MinValue 也将写为“ZeroDateString”。所有其他字符串由基础 IsoDateTimeConverter 类处理。 我在 DateTime 属性的 JsonNet 注释上使用此转换器。

有没有更好、更简单的方法来处理这个问题,例如在更基本的层面上,不需要注释?

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

【问题讨论】:

  • 为什么不简单地在 JSON 中允许空值并使用 DateTime?,而不是使用标记值? .NET“零日期”是 0001-01-01,SQL Server 不允许 1753-01-01 之前的日期,这东西很快就会变得混乱。
  • 将这些值存储为可为空的 DateTime 值可能是更好的方法。这很容易实现。但我仍然需要处理传入的“0000...” JSON 值
  • 使用示例注释中的日期格式可能应该将小时指定为 24 小时格式:yyyy-MM-dd HH:mm:ss 而不是 yyyy-MM-dd hh:mm:ss

标签: c# datetime json.net converter


【解决方案1】:

我遇到了同样的问题,为此我使用了自定义转换器...

class MyDateConverter: Newtonsoft.Json.Converters.IsoDateTimeConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.Value != null && reader.Value.ToString().StartsWith("0000")) return null;
        else return base.ReadJson(reader, objectType, existingValue, serializer);
    }
}

【讨论】:

    【解决方案2】:

    您可以按照文档中的说明使用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 指出的那样,您应该只使用“常规”行为,以免以后遇到麻烦,并且在使用日期的任何地方都必须遵循此自定义逻辑。 p>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-05
      • 2010-11-24
      • 1970-01-01
      • 2017-10-03
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 2016-02-14
      相关资源
      最近更新 更多