Search code examples
c#datetimejson.net

Supporting multiple custom DateTime formats when deserializing with Json.Net


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?


Solution

  • 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