我想支持使用Newtonsoft Json反序列化器反序列化多个自定义DateTime格式,因此我正在使用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" });
但是,以上代码的结果仅支持反序列化第一种格式。
如何实现对多种自定义DateTime格式的支持?
答案 0 :(得分:4)
如果要处理多种可能的日期格式,则需要制作一个自定义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" }
});
答案 1 :(得分:0)
我想提出一个同时支持DateTime和DateTimeOffset以及可空性的版本。
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;
}
}