I want to support deserializing more than one custom DateTime format with the Newtonsoft Json deserializer, so I am using IsoDateTimeConverter
:
var serializeSettings = new JsonSerializerSettings();
serializeSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyyMMddTHHmmssZ" });
As the DateTimeFormat
property does not accept an array of formats, I tried the following to support multiple custom date formats:
var serializeSettings = new JsonSerializerSettings();
serializeSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyyMMddTHHmmssZ" });
serializeSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-ddTHH:mm" });
However the above code's result is supporting deserializing only the first format.
How can I achieve supporting multiple custom DateTime formats?
public class MyObject { [JsonConverter (typeof (CustomDateTimeConverter))] public DateTime Date {get;set;} } and then deserialize in using any normal way you did before... MyObject obj = JsonConvert.DeserializeObject<MyObject> (json);
If you want to handle multiple possible date formats, you will need to make a custom JsonConverter which can accept multiple format strings and try them all until one succeeds. Here is a simple example:
Serializing and deserializing JSON payloads from the network are common operations. Extension methods on HttpClient and HttpContent let you do these operations in a single line of code. These extension methods use web defaults for JsonSerializerOptions.
Use the library directly, not through a framework such as ASP.NET Core. Use the JsonSerializer class with custom types to serialize from and deserialize into. For information about how to read and write JSON data without using JsonSerializer, see How to use the JSON DOM, Utf8JsonReader, and Utf8JsonWriter.
If you want to handle multiple possible date formats, you will need to make a custom JsonConverter
which can accept multiple format strings and try them all until one succeeds. Here is a simple example:
class MultiFormatDateConverter : JsonConverter
{
public List<string> DateTimeFormats { get; set; }
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime) || objectType == typeof(DateTime?);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string dateString = (string)reader.Value;
if (dateString == null)
{
if (objectType == typeof(DateTime?))
return null;
throw new JsonException("Unable to parse null as a date.");
}
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();
}
}
Then you can add it to your settings like this:
var settings = new JsonSerializerSettings();
settings.DateParseHandling = DateParseHandling.None;
settings.Converters.Add(new MultiFormatDateConverter
{
DateTimeFormats = new List<string> { "yyyyMMddTHHmmssZ", "yyyy-MM-ddTHH:mm" }
});
Fiddle: https://dotnetfiddle.net/vOpMEY
I want to propose version which supports both DateTime and DateTimeOffset and nullability as well.
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With