1

is there any way to convert date read from JSON file? Exemplary record from my file is:

{
    "UserID": 73274,
    "Created": "17-03-2018 06:35",
    "Office": "Washington"
},

What I am doing is importing JSON file and save its content to database. The problem is, when date is in DD-MM-YYYY hh:ss format, it simply doesn't work. But when date is in YYYY-MM-DDThh:mm:ss format, everything is fine. How to parse date to another format after reading this file and execute following operations on file with parsed date?

Part of my controller responsible for this operations is:

if (file.ContentType == "application/json")
{
    try
    {
        using (var reader = new StreamReader(file.OpenReadStream()))
        {
            content = reader.ReadToEnd();
        }
     }
     catch
     {
         return BadRequest(Messages.fileNotChosen);
     }
     try
     {
         userObjects = JsonConvert.DeserializeObject<List<UserImportModel>>(content);
     }
     catch
     {
         return BadRequest();
     }
 }

When date format is YYYY-MM-DDThh:mm:ss, userObjects is properly counted and controller moves to part where I execute adding to database. When date format is DD-MM-YYYY hh:ss, userObjects = 0 and controller moves to catch, which then returns BadRequest().

EDIT: Code of UserImportModel class:

public class UserImportModel
{

    public string UserID { get; set; }

    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
    public DateTime Created { get; set; }

    public string Office { get; set; }

}
Antoine V
  • 6,998
  • 2
  • 11
  • 34
Kamil
  • 111
  • 13
  • possible duplicate of [this question](https://stackoverflow.com/questions/919244/converting-a-string-to-datetime) – Lucas Wieloch Sep 10 '18 at 12:56
  • 1
    There's a solution here for Json.Net if the format is fixed: https://stackoverflow.com/questions/21256132/deserializing-dates-with-dd-mm-yyyy-format-using-json-net But if you have a mix of date formats then you may need to deserialise the string manually. – Rup Sep 10 '18 at 12:58
  • Imho an [XY Problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). You should always pass and return your date as ISO dates, since you don't necessarily know the users globalization settings. The UI (WPF, WinForms, HTML/JavaScript, Angular etc) should take that ISO time (it contains time zone information and more) and show it in the users language format and time zone – Tseng Sep 10 '18 at 14:37

2 Answers2

2

If you need to deserialize date in different formats, you have to create a custom JsonConverter:

public class MultiFormatDateTimeConverter : JsonConverter
{
    private List<string> formats;

    public MultiFormatDateTimeConverter(List<string> formats)
    {
       this.formats = formats;
    }

    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;

        foreach (string format in formats)
        {
            if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime 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();
    }
}

Usage example:

var settings = new JsonSerializerSettings();
settings.DateParseHandling = DateParseHandling.None;
settings.Converters.Add(new MultiFormatDateTimeConverter(new List<string> { "DD-MM-YYYY hh:ss", "YYYY-MM-DDThh:mm:ss" }));

userObjects = JsonConvert.DeserializeObject<List<UserImportModel>>(content, settings);
Alex Riabov
  • 8,655
  • 5
  • 47
  • 48
  • Your solution did the job. It also allows me to specify many date formats to be converted to ISO8601 standard, so I will stick to it. Thank you very much. – Kamil Sep 10 '18 at 20:40
1

JSON.Net uses the Standard 8601 to represent Date-Time. The extended format for a complete date-time expression is: "YYYY-MM-DDTHH:MM:SS". The JSON.Net "Deserializer" method (DeserializeObject) is overloaded for acceptting custom formatters, you can use de IsoDateTimeConverter specifying in the DateTimeFormat property the format of your string "dd"

userObjects = JsonConvert.DeserializeObject<List<UserImportModel>>(content, 
                   new IsoDateTimeConverter { DateTimeFormat = "dd-MM-yyyy hh:mm:ss" });

Another alternative is to use a regular expresion to replace all bad formed ISO Dates in your JSON string before calling the DeserializeObject method.

ArBR
  • 4,032
  • 2
  • 23
  • 29
  • 1
    I tried to use **IsoDateTimeConverter** as I found similar solution in other thread, but it didn't work for me. Turned out I specified in **DateTimeFormat** property format of date that I wanted to have instead one I had in my JSON file. What a shame. Using regular expressions is also good idea if everything other fails. – Kamil Sep 10 '18 at 20:19