2

I've noticed that when parsing JSON using the Newtonsoft.Json.Linq namespace, selecting a date value returns a string in a different format to that of the original JSON. What is causing this?

For example:

JSON

[
  {
    ...
    "commit": {
      ...
      "committer": {
        "name": "GitHub",
        "email": "[email protected]",
        "date": "2016-12-19T11:53:13Z"
      },
      ...
    }
    ...
  }
  ...
]

C#

...
List<Commit> commits = new List<Commit>();
JArray commitsArray = JArray.Parse(rawCommits);
...
foreach (var entry in commitsArray)
{
    DateTime date;
    CultureInfo provider = CultureInfo.InvariantCulture;
    string format = "MM/dd/yyyy HH:mm:ss";

    try
    {
        date = DateTime.ParseExact((string)entry["commit"]["committer"]["date"], format, provider);
    }
    catch (FormatException ex)
    {
        date = new DateTime(0);
    }
    ...
}
...

rawCommits is a string representation of the raw JSON obtained using Microsoft.AspNetCore.WebUtilities.HttpRequestStreamReader().

I would expect (string)entry["commit"]["committer"]["date"] to return the same string as is in the JSON, in this instance in the format "yyyy-MM-ddTHH:mm:ssz" but as the above snippet shows it is instead in the format "MM/dd/yyyy HH:mm:ss". Why has the format changed and what has happened to the time and timezone identifiers?

The only thing I can think is that the call to JArray.Parse(string) identifies and manipulates the date. Is this the case? If so, surely it is undesirable behaviour? If not, what is going on?

Edit This can be produced with the following example in an .Net Core Console App, adding "Microsoft.AspNetCore.Mvc": "1.1.0" to the project.json file:

using Newtonsoft.Json.Linq;
using System;

namespace JsonExample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            string json = "{\"date\": \"2016-12-19T11:53:13Z\"}";
            JToken jToken = JToken.Parse(json);

            Console.WriteLine(jToken["date"]);
            Console.ReadLine();
        }
    }
}

With an output of 19/12/2016 11:53:13, which is interesting because it is yet another format (dd/MM/yyyy HH:mm:ss). Does this perhaps have anything to do with localisation settings? If so, why? It's also confusing, given that IIS Express is running on the same machine as that on which I executed the above code, yet I thought it took the host machines localisation. It also means if I deploy to a server with different localisation than my development machine the format specifier in the original post will because an exception and I'll end up with a value equal to new DateTime(0). What is it I am not understanding?

2 Answers 2

2

You are correct, the call to JArray.Parse is parsing the date for you automatically (by design).

I think to get at the raw string you need to use the reader directly:

var s = @"[{
            ""commit"": {
                ""committer"": {
                    ""name"": ""GitHub"",
                    ""email"": ""[email protected]"",
                    ""date"": ""2016-12-19T11:53:13Z""
                }
            }
        }
    ]";

    using (var sr = new StringReader(s))
    using (var jr = new JsonTextReader(sr) { DateParseHandling = DateParseHandling.None })
    {
        var arr = JArray.ReadFrom(jr);

        foreach (var entry in arr)
        {
            Console.WriteLine(entry["commit"]["committer"]["date"].ToString()); // 2016-12-19T11:53:13Z
        }
    }
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, both for the example and the link to the GitHub conversation on the issue. Seems like an undesirable effect, but if the library's author likes the functionality then I guess what will be will be!
As it turns out, the simplest solution for what I want to achieve is to cast the result to DateTime: DateTime date = (DateTime)entry["commit"]["committer"]["date"];. Not sure why that didn't occur to me previously, although it's useful to know about the DateParseHandling option for if I explicitly need the raw string.
0

Json.Net stores date-looking values as dates internally, not as strings (it does the same for other base data types as well). So when you start to manipulate these values, you are actually dealing with the internal representation of that value which is a date type, and when you then get it out as a string, you're getting back a string conversion of that internal value, not the original string as you are expecting.

This is a notable difference between dealing with JSON in JS vs. using Json.Net in C# - an unfortunate one IMHO as it requires additional code to work around.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.