2

I am using NodaTime throughout my project as a replacement for the standard BCL DateTime classes, with amazing results.

I would like to banish DateTime from my project completely. I am only using it in one place - where I deserialize a large JSON file that contains dates. These dates are always UTC and always specified in ISO 8601 format.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;

namespace Foo.Parsing
{
public class Parser
{
    JSchema schema;
    JObject jsonObject;

    public Parser(string jsonContent, string schemaString)
    {
        schema = JSchema.Parse(schemaString);
        jsonObject = JObject.Parse(jsonContent);
    }

    public MyObject Parse()
    {
        return jsonObject.ToObject<MyObject>();
    }
}

public class MyObject
{
     [JsonProperty(Required = Required.Always)]
     public DateTime date { get; set; }

     // A lot of other properties here.
}
}

This all works extremely well, but at the moment I have to use Instant.FromDateTimeUtc(myObject.date); to convert the DateTimes to Instant. Inside MyObject I have DateTimes and if I try to change this to Instant, I get the following error:

Newtonsoft.Json.JsonSerializationException' in Newtonsoft.Json.dll Additional information: Error converting value 2016/07/07 12:00:00 AM to type 'NodaTime.Instant'. Path 'date', line 4, position 37

Is there any way for me to deserialize my JSON file to my strongly typed MyObject, with my dates deserializing directly to Instant instead of having to convert a DateTime?

08Dc91wk
  • 4,254
  • 8
  • 34
  • 67
  • 2
    Are you using the [`NodaTime.Serialization.JsonNet` package](https://www.nuget.org/packages/NodaTime.Serialization.JsonNet)? It has converters that should help with this. See [Deserializing Noda Time's LocalDateTime with JSON.NET](http://stackoverflow.com/q/21050002/10263) for details on setting this up. – Brian Rogers Jul 20 '16 at 17:15
  • Thanks, that has gotten me a step further, though now I am getting a error saying "Unexpected token parsing Instant. Expected String, got Date." How does the JObject know that it's a date? I notice when I set MyObject.date to be a string rather than an Instant/DateTime it comes back in a different (non ISO) format, so something in JObject.Parse seems to be recognising the format as a date... – 08Dc91wk Jul 20 '16 at 18:48

1 Answers1

3

Per the Noda Time User Guide:

If you're still getting "Unexpected token..." messages, then likely you have changed the DateParseHandling setting. The ConfigureForNodaTime call will set this to DateParseHandling.None, and it should be left that way.

Note that this works well with the JsonConvert.SerializeObject and JsonConvert.DeserializeObject classes, as they accept a JsonSettings parameter, which can also be set via JsonConvert.DefaultSettings. Here is a live demo using this approach.

However, if you're using the JObject APIs, there is one slight problem. JObject.Parse has no ability to take a settings parameter, and by default you won't have the DateParseHandling.None that is required at this stage. The solution to this involves using a JsonTextReader, and is described well in this StackOverflow answer.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • No, I call Configure right before I deserialize. I tried adding "DateParseHandling.None" as follows. Still no dice: `JsonSerializer serializer = new JsonSerializer();` `serializer.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);` `serializer.DateParseHandling = DateParseHandling.None;` `return jsonObject.ToObject(serializer);` – 08Dc91wk Jul 20 '16 at 19:43
  • See my updated answer. I believe the last part address your current issue. – Matt Johnson-Pint Jul 20 '16 at 20:31