代码之家  ›  专栏  ›  技术社区  ›  Yahya Hussein

使用json.net反序列化时支持多种自定义日期时间格式

  •  3
  • Yahya Hussein  · 技术社区  · 7 年前

    我想用newtonsoft json反序列化程序支持反序列化多个自定义日期时间格式,因此我使用 IsoDateTimeConverter 以下内容:

    var serializeSettings = new JsonSerializerSettings();
    serializeSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyyMMddTHHmmssZ" });
    

    作为 DateTimeFormat 属性不接受格式数组,我尝试了以下操作以支持多种自定义日期格式:

    var serializeSettings = new JsonSerializerSettings();
    serializeSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyyMMddTHHmmssZ" });
    serializeSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-ddTHH:mm" });
    

    然而,上述代码的结果是只支持反序列化第一种格式。

    如何实现支持多种自定义日期时间格式?

    1 回复  |  直到 7 年前
        1
  •  5
  •   Brian Rogers    7 年前

    如果要处理多种可能的日期格式,则需要自定义 JsonConverter 它可以接受多个格式字符串并尝试所有这些字符串,直到一个成功为止。下面是一个简单的例子:

    class MultiFormatDateConverter : JsonConverter
    {
        public List<string> DateTimeFormats { get; set; }
    
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(DateTime);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            string dateString = (string)reader.Value;
            DateTime date;
            foreach (string format in DateTimeFormats)
            {
                // adjust this as necessary to fit your needs
                if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
                    return date;
            }
            throw new JsonException("Unable to parse \"" + dateString + "\" as a date.");
        }
    
        public override bool CanWrite
        {
            get { return false; }
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    然后可以将其添加到设置中,如下所示:

    var settings = new JsonSerializerSettings();
    settings.DateParseHandling = DateParseHandling.None;
    settings.Converters.Add(new MultiFormatDateConverter 
    { 
        DateTimeFormats = new List<string> { "yyyyMMddTHHmmssZ", "yyyy-MM-ddTHH:mm" } 
    });
    

    小提琴: https://dotnetfiddle.net/vOpMEY

        2
  •  0
  •   codevision Ohad Schneider    6 年前

    我想推荐同时支持datetime和datetimeoffset以及nullability的版本。

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;
    
    internal class MultiFormatDateConverter : DateTimeConverterBase
    {
        public IList<string> DateTimeFormats { get; set; } = new[] { "yyyy-MM-dd" };
    
        public DateTimeStyles DateTimeStyles { get; set; }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var val = IsNullableType(objectType);
            if (reader.TokenType == JsonToken.Null)
            {
                if (!val)
                {
                    throw new JsonSerializationException(
                        string.Format(CultureInfo.InvariantCulture, "Cannot convert null value to {0}.", objectType));
                }
            }
    
            Type underlyingObjectType = val ? Nullable.GetUnderlyingType(objectType)! : objectType;
            if (reader.TokenType == JsonToken.Date)
            {
                if (underlyingObjectType == typeof(DateTimeOffset))
                {
                    if (!(reader.Value is DateTimeOffset))
                    {
                        return new DateTimeOffset((DateTime)reader.Value);
                    }
    
                    return reader.Value;
                }
    
                if (reader.Value is DateTimeOffset)
                {
                    return ((DateTimeOffset)reader.Value).DateTime;
                }
    
                return reader.Value;
            }
    
            if (reader.TokenType != JsonToken.String)
            {
                var errorMessage = string.Format(
                    CultureInfo.InvariantCulture,
                    "Unexpected token parsing date. Expected String, got {0}.",
                    reader.TokenType);
                throw new JsonSerializationException(errorMessage);
            }
    
            var dateString = (string)reader.Value;
            if (underlyingObjectType == typeof(DateTimeOffset))
            {
                foreach (var format in this.DateTimeFormats)
                {
                    // adjust this as necessary to fit your needs
                    if (DateTimeOffset.TryParseExact(dateString, format, CultureInfo.InvariantCulture, this.DateTimeStyles, out var date))
                    {
                        return date;
                    }
                }
            }
    
            if (underlyingObjectType == typeof(DateTime))
            {
    
                foreach (var format in this.DateTimeFormats)
                {
                    // adjust this as necessary to fit your needs
                    if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture, this.DateTimeStyles, out var date))
                    {
                        return date;
                    }
                }
            }
    
            throw new JsonException("Unable to parse \"" + dateString + "\" as a date.");
        }
    
        public override bool CanWrite
        {
            get { return false; }
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public static bool IsNullableType(Type t)
        {
            if (t.IsGenericTypeDefinition || t.IsGenericType)
            {
                return t.GetGenericTypeDefinition() == typeof(Nullable<>);
            }
    
            return false;
        }
    }