Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Newtonsoft.Json.Linq.JObject.ToObject() converting date in string format

I'm building a .net core library. The error is true for 1.1 as well as 2.0.

I have a JObject (I read a bunch of other answers where people tell the OP to just do JsonConvert.Deserialize(obj), that's not an option, I need to have it).

That JObject has a date in a string, and I'm going to deserialize it to an object that also has it as a string, and I need to have it in the same format as it is provided.

One answer I saw claims that as soon the object becomes a JObject the date is parsed to that format, but I found that that's not the case and .ToObject() is where this conversion is actually happening.

I searched a lot on here and found a couple of accepted solutions that do not work for me.

  1. Setting DateParseHandling.None
  2. Explicitly specifying the date format.(tried the other approach in this answer as well)

None of those worked.

Testing code:

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace JobjectDateTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var json = @"{""Data"": {""CreatedAt"":""2018-01-04T14:48:39.7472110Z""}}";
            var thing = JsonConvert.DeserializeObject<Thing>(json);
            Console.WriteLine(thing.Data.First); // "CreatedAt": "2018-01-04T14:48:39.747211Z"

            var jsonSer = new JsonSerializer { DateFormatString = "yyyy-MM-ddTHH:mm:ssZ" };
            var innerThing = thing.Data.ToObject<InnerThing>(jsonSer);

            Console.WriteLine(innerThing.CreatedAt); // 01/04/2018 14:48:39
            Console.WriteLine(innerThing.CreatedAt == "2018-01-04T14:48:39.7472110Z"); // false

            jsonSer = new JsonSerializer { DateParseHandling = DateParseHandling.None };
            innerThing = thing.Data.ToObject<InnerThing>(jsonSer);

            Console.WriteLine(innerThing.CreatedAt); // 01/04/2018 14:48:39
            Console.WriteLine(innerThing.CreatedAt == "2018-01-04T14:48:39.7472110Z"); // false
        }

        class Thing
        {
            public JObject Data { get; set; }
        }

        class InnerThing
        {
            public string CreatedAt { get; set; }
        }
    }
}
like image 317
LLL Avatar asked Jan 29 '23 22:01

LLL


2 Answers

You've been experimenting when serializing the data, but the conversion is happening when you deserialize the JSON to start with. That's where you need to disable DateParseHandling. Here's the change you need:

var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None };
var thing = JsonConvert.DeserializeObject<Thing>(json, settings);

New output:

"CreatedAt": "2018-01-04T14:48:39.7472110Z"
2018-01-04T14:48:39.7472110Z
True
2018-01-04T14:48:39.7472110Z
True

You can see the difference in the JObject this way:

var property = (JProperty) thing.Data.First;
var value = (JValue) property.Value;
Console.WriteLine(value.Type);

Before specifying the settings, this prints Date. With the settings preventing date parsing, this prints String.

like image 93
Jon Skeet Avatar answered Jan 31 '23 19:01

Jon Skeet


I had a similar problem and solved it with

JToken rootObj = JsonConvert.DeserializeObject<dynamic>(myJsonString, new JsonSerializerSettings { DateParseHandling = DateParseHandling.None }) as JToken;

As others wrote, once you have the JObject / JToken it is already too late for the DateParseHandling, and the DateParseHandling is not available for the JToken.Parse().

JToken rootObj = JsonConvert.DeserializeObject<dynamic>(myJsonString, new JsonSerializerSettings { DateParseHandling = DateParseHandling.None }) as JToken;
if (rootObj.Children<JProperty>().Count() != 1) Console.WriteLine($"Error: json no or multiple root tokens");
JProperty rootProp = rootObj.Children<JProperty>().First(); // with the property you can access the name if needed
if (rootProp.Name.Equals("theTokenNameIAmLookingFor"))
   {
      Console.WriteLine($"found my token name: {rootProp.Name}");
      MyClass myObj = rootObj.ToObject<MyClass>();
   }
like image 22
Robbie Avatar answered Jan 31 '23 19:01

Robbie