Json.Net messes up timezones for DateTimeOffset when serializing - c#

I have looked at a lot of related questions but none of them seem to be working for me.
I'm trying to serialize everything in UTC. Here's my code:
class Class1
{
static void Main()
{
Class2 foo = new Class2();
JObject json = JObject.Parse(JsonConvert.SerializeObject(foo, new JsonSerializerSettings()
{
DateParseHandling = DateParseHandling.DateTimeOffset,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Utc
}));
Console.WriteLine(json.ToString());
Console.Read();
}
}
class Class2
{
public DateTimeOffset time = new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(14663484000000000));
public DateTimeOffset time2 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(14663484000000000);
public DateTime time3 = new DateTime(14663484000000000);
}
Here's the output:
{
"time": "2016-06-19T08:00:00-07:00",
"time2": "2016-06-19T08:00:00-07:00",
"time3": "0047-06-20T15:00:00Z"
}
Here's the output I'm trying to get:
{
"time": "2016-06-19T15:00:00+00:00",
"time2": "2016-06-19T15:00:00+00:00",
"time3": "0047-06-20T15:00:00+00:00"
}
As you can see, the DateTimeOffset properties are not converted at all. The DateTime is, but the timezone is indicated using Z whereas I'm trying to use +00:00.

In your code, you are doing the following:
Serializing an instance of Class2 to a JSON string using specific DateTime-related serialization settings.
Deserializing to a JToken hierarchy without using those settings.
(Making additional modifications to the hierarchy - not shown.)
Serializing the JToken hierarchy to a final string (via json.ToString()) again without using those settings.
When you do, formatting settings for dates chosen in step #1 get lost.
To solve this, you need to apply the settings every time you serialize from or to a JSON string representation, since, as explained in this documentation page, JSON does not have an "official" format for dates. Because of this, Json.NET applies heuristics for recognizing and formatting dates whenever it converts from and to a JSON string representation - which you are doing not once but thrice.
You could accomplish this by doing:
var settings = new JsonSerializerSettings()
{
DateParseHandling = DateParseHandling.DateTimeOffset,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Utc
};
// Generate initial serialization
var initialString = JsonConvert.SerializeObject(foo, settings);
// Parse back to JToken
var json = JsonConvert.DeserializeObject<JObject>(initialString, settings);
// Make modifications as required
// json["foo"] = "bar";
// Generate final JSON.
var finalString = JsonConvert.SerializeObject(json, Formatting.Indented, settings);
To improve efficiency, you could use JToken.FromObject() (or JObject.FromObject() if you prefer) to generate the JToken hierarchy without needing to create and parse an initial string representation:
var settings = new JsonSerializerSettings()
{
DateParseHandling = DateParseHandling.DateTimeOffset,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Utc
};
var json = JToken.FromObject(foo, JsonSerializer.CreateDefault(settings));
// Make modifications as required
// json["foo"] = "bar";
// Generate final JSON.
var finalString = JsonConvert.SerializeObject(json, Formatting.Indented, settings);
Note, however, that Json.NET will output a UTC DateTime in the format "0047-06-20T15:00:00Z" rather than "2016-06-19T15:00:00+00:00" for reasons explained here. If you need your UTC DateTime properties to be serialized in DateTimeOffset format you might need to use a custom converter.

Related

How to deserialize string to JObject without scientific notation in C#

I have a string like this:
var str = "{'data': {'someProperty': 0.00001}}";
When I parse it to JObject like that
var jObject = JObject.Parse(str);
My jObject looks like this:
{"data": {"someProperty": 1E-05}}
I need to get rid of scientific notation so that resulting JObject would look like original json.
I managed to do that using later version of Newtonsoft.Json like that:
var serializer = new JsonSerializer { FloatParseHandling = FloatParseHandling.Decimal };
using (System.IO.TextReader tr = new System.IO.StringReader(str)
using (var jsonReader = new JsonTextReader(tr))
{
var jp = serializer.Deserialize(jsonReader);
var jObject = JObject.FromObject(jp);
}
But I need to achieve the same result using Newtonsoft.Json version 3.5 which does not have a FloatParseHandling property. I guess I need to implement a JsonConverter somehow, but I have no idea how to do that, since my real json is much more complex than the one in example and I need to handle all the float values in it the right way.
So, what would be the right way to get a JObject without a scientific notation for float values using Newtonsoft 3.5?
Following produces the object you are looking for
JObject.Load(new JsonTextReader(new StringReader(str)) { FloatParseHandling = FloatParseHandling.Decimal }, null)
taken from here:
EDIT:
JTokenTypes in NewtonSoft v 3.5.8 are limited to Float and Integer (in regards to decimal). There is no decimal type in that version and thus makes it not possilbe to have a decimal value in that JObject.
JTokenTypes from v3 of newtonsoft
None = 0,
Object = 1,
Array = 2,
Constructor = 3,
Property = 4,
Comment = 5,
Integer = 6,
Float = 7,
String = 8,
Boolean = 9,
Null = 10,
Undefined = 11,
Date = 12,
Raw = 13,
Bytes = 14
The right way to do this would be to upgrade the Newtonsoft package :)
Jawad's provided code is not the best solution because it will end up in memory leaks. StringReader and JsonTextReader are both implementing the IDisposable interface and therefore must be disposed if they are not used anmyore.
Safer code would be:
public JObject CustomJObjectLoad(string str)
{
using (var stringReader = new StringReader(str))
{
using (var jsonReader = new JsonTextReader(stringReader) { FloatParseHandling = FloatParseHandling.Decimal })
{
return JObject.Load(jsonReader, null);
}
}
}
You can also create simple POCO object. and make sure someProperty is of type string and then de-serialize the json string
var myObject = Newtonsoft.Json.JsonConvert.DeserializeObject<YourObject>(json)
First, your json isn't valid :)
It should have double quotes:
{"data": {"someProperty": 0.00001}}
But even better, using standard casing, would be:
{"Data": {"SomeProperty": 0.00001}}
And then, we can do this:
var str = "{\"Data\": {\"SomeProperty\": 0.00001}}";
dynamic myObject = JsonConvert.DeserializeObject(str);
var val = myObject.Data.SomeProperty.ToString("0." + new string('#', 339));
val will then be: "0.00001"
(Note: I stole the solution from: Double to string conversion without scientific notation)

Keep same Datetime format while reading from JSON in C#

I have a JSON content like this
"started_on": "2017-12-01",
"start_time": "2017-12-01T10:00:00+00:00",
"finish_time": "2017-12-01T11:00:00+00:00",
I want to read the start time and end time as a string in same format and i tried the below code for doing the same
JObject _task = JObject.Parse(response_json);
string _description = "\n start_time:" + (string)_task["start_time"];
_description += "\n finish_time:" + (string)_task["finish_time"];
This reads from JSON correctly , but when i check the datetime format i can see this as like "12/01/2017" only.
How can i keep the same format while doing the conversion and i want the text as it is in the JSON parameter
You need to instruct JSON.NET to read them as strings:
var settings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None
};
JObject _task = JsonConvert.DeserializeObject<JObject>(response_json, settings);
If you need to get some of the values as DateTime objects after they have all been read as strings, you can use this:
var dt = _task["property"].Value<DateTime>();
Although at this stage you may just want to create a class to represent your JSON:
public class MyTask
{
public DateTime Property1 {get;set;} // property1 will be read as a DateTime
public string Property2 {get;set;} // property2 will be read as a string
}
MyTask _task = JsonConvert.DeserializeObject<MyTask>(response_json);

Json parse date time format

I'm using Newtonsoft.Json to parse json objects but one object that have date and time in it wont be parsed as it's stated.
JObject a = JObject.Parse(response);
a will get the whole json and last is the object i want.
, "last_activity_date": "2017-03-29T18:05:38.707Z"}
var date = a["last_activity_date"];
will output
date = 2017-03-29 18:05:38
Is it possible to keep the date time as it is? 2017-03-29T18:05:38.707Z
Or do i need to use regex?
Due to default JObject parsing configuration, your last_activity_date will be treated as Date type, if you want to treat it as a string, you'll need to create dedicated class and deserialize your JSON into object.
public class Root
{
[JsonProperty("last_activity_date")]
public string LastActivityDate { get; set; }
}
You can use JsonConvert:
var obj = (Root)JsonConvert.DeserializeObject(json, typeof(Root));
Console.WriteLine(obj.LastActivityDate); //outputs: 2017-03-29T18:05:38.707Z

Json.Net parsing datetime value error

I am trying to convert a json string to a JObject using JObject.Parse, but running into the error "Error parsing positive infinity value. Path 'Modified.Date', line 1, position 52."
Here is the part of json that is throwing the error on -
{ ..., "Modified" : { "Date" : ISODate("2013-02-21T22:23:57.118Z"), "User" : "Admin" }, ...}
Here is the code I am using to do the parse -
var jobj = JObject.Parse(formJson)
Update: The json was generated by using mongodb's .ToJson() extension method, by sending in the following jsonwritersettings it generated json that was parsable by json.net - new JsonWriterSettings { OutputMode = JsonOutputMode.JavaScript };
I think you need to lose the ISODate.
This works:
String MyJson = "{MyDate : \"2013-02-21T22:23:57.118Z\" }";
var x = Newtonsoft.Json.Linq.JObject.Parse(MyJson);
I tried using Regex and convert in C#:
Regex _regex = new Regex(#"\d\d\d\d-\d\d-\d\d");
Match _date = _regex.Match(<Your_Date_String>);
if (_date.Success)
{
var datetime = Convert.ToDateTime(_date.Value);
}

Custom Json serialization

I have a list of KeyPairValue wich I serialize in Json Object using JavaScriptSerializer. The output of this operation give me something like this :
[{"Key":"A","Value":"ValueA"},{"Key":"D","Value":"ValueD"}]
I'ld like to get rid of those "" around the property name so it could look like this :
[{ Key:"A", Value:"ValueA"},{ Key:"D", Value:"ValueD"}]
Is there a way to achieve this or if what i'm looking for is just not a Json serialization ?
You can achieve it with Json.Net
StringWriter str = new StringWriter();
JsonTextWriter writer = new JsonTextWriter(str);
writer.QuoteName = false; //<-- This is the trick
JsonSerializer jsonSer = new JsonSerializer();
jsonSer.Serialize(writer, new { ID = 1, Name = "Jack" });
string jsonstr = str.ToString();
Output is {ID:1,Name:"Jack"}
As I know it is a must requirement by JSON to embedd your keys in "". This is because JSON is actually a transport format for JavaScript objects and therefore it has some specifics.
The RFC specifies that a name is a string, and it also specifies that a string must be wrapped in quotation marks.
RFC 4627
It's worth noting the different types that values can be and that some of the types don't have to be wrapped in quotes. You can find this in the spec as well.

Categories