json.net and wrong dates with +00:00 suffix - c#

I serialize objects having DateTime properties, like this: JsonConvert.SerializeObject(my_object), then on another machine I deserialize: result = JsonConvert.DeserializeObject<Result>(r);. And some dates are wrong. I've checked through fiddler that when date in json looks like this Date=2014-11-29T18:41:41.1672899 then it's deserialized correctly, but every 10th or so entry looks like Date=2014-11-29T18:55:39.1175417+00:00 (note the +00:00) and then it's deserialized as date shifted by two hours. Why is this and how to fix this?

You can explicitly set DateTimeZoneHandling to DateTimeZoneHandling.Utc on JsonSerializerSettings:
Result result = JsonConvert.DeserializeObject<Result>(r, new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc
});

Related

How to correctly deserialize a Json DateTimeOffset?

i got a problem while i try to deserialize a DateTimeOffset from a json. I saw a lot of questions here, but no one seems to work. I got from Json this dateTime : 05/04/2019 02:39:33 PM GMT and i want to keep the offset to zero. After the deserialization, by the way, i got my object with same exact time(In this case 02:39:33 PM) but with my time zone ( +02:00). I tried these two workaround, without success:
First of all, i tried to setup setting to my deserializer:
JsonSerializerSettings serializerSettings = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
DateParseHandling = DateParseHandling.DateTimeOffset,
DateFormatString = "dd/MM/yyyy hh:mm:ss tt 'GMT'"
};
I tried this converter too:
class DateFormatConverter : IsoDateTimeConverter
{
public DateFormatConverter(string format)
{
DateTimeFormat = format;
DateTimeStyles = System.Globalization.DateTimeStyles.AssumeUniversal;
}
So, i expected this reseult:
05/04/2019 02:39:33 PM +00:00
thanks to all that will answer me!
Maybe change DateParseHandling.DateTimeOffset to DateParseHandling.None?
I managed to got the expected result by change DateParseHandling = DateParseHandling.None in the Setting of serializer.

JSON Date and DateTime serialisation in c# & newtonsoft

We are sending JSON to an API defined by swagger that some properties are DateTime in the format yyyy-MM-ddThh:mm:ss.000Z (the milliseconds must be 3 digits or it fails validation at the endpoint) and some are Date (no time) properties.
I have seen many messages saying use the formatters like this:
var jsonSettings = new JsonSerializerSettings();
jsonSettings.DateFormatString = "yyyy-MM-ddThh:mm:ss.000Z"; //try .fffZ too
var jsonObject= Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json , setting);
but this does not convert the DateTimes into the correct format, and how does C# deal with a Date only type? It always seems to serialise as DateTime.MinValue()
Here is an example:
Someone sends me json as string but the the dates and datetimes in the incorrect format to be sent to the endpoint. I was hoping that the swagger class and json deserialisation would format them but it is not.
This is the swagger generated class
public class OurSwaggerObject
{
[Newtonsoft.Json.JsonProperty("dateTimeField", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required]
[System.ComponentModel.DataAnnotations.RegularExpression(#"^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$")]
public DateTime dateTimeField { get; set; }
[Newtonsoft.Json.JsonProperty("dateField", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required]
[System.ComponentModel.DataAnnotations.RegularExpression(#"^\d{4}-\d\d-\d\d$")]
public DateTime dateField { get; set; }
}
So I try and coerce the json to be correct but I'm doing it wrong or something is missing
string json = #"{ 'dateTimeField': '1995-04-07T00:00:00',
'dateField': '1995-04-07T00:00:00'
}";
/* The json we need to satisfy the swagger endpoint is:
{ 'dateTimeField': '1995-04-07T00:00:00.000Z',
'dateField': '1995-04-07'
}
*/
OurSwaggerObject deserialisedIntoObject = Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json);
string serialisedToString = Newtonsoft.Json.JsonConvert.SerializeObject(deserialisedIntoObject);
//serialisedToString= "{\"dateTimeField\":\"1995-04-07T00:00:00\",\"dateField\":\"1995-04-07T00:00:00\"}"
var jsonSettings = new JsonSerializerSettings();
jsonSettings.DateFormatString = "yyyy-MM-ddThh:mm:ss.fffZ"; //this won't help much for the 'date' only field!
deserialisedIntoObject = Newtonsoft.Json.JsonConvert.DeserializeObject<OurSwaggerObject>(json,jsonSettings);
serialisedToString = Newtonsoft.Json.JsonConvert.SerializeObject(deserialisedIntoObject, jsonSettings);
//serialisedToString="{\"dateTimeField\":\"1995-04-07T00:00:00\",\"dateField\":\"1995-04-07T00:00:00\"}"
As I mentioned in a comment, there is no standard date representation in JSON. The ISO8601 is the de-facto standard, ie most people started using this some years ago. ISO8601 does not require milliseconds. If the other endpoint requires them, it's violating the defacto standard.
Json.NET has been using IOS8601 since version 4.5. The current one is 10.0.3. The following code :
JsonConvert.SerializeObject(DateTime.Now)
returns
"2017-09-08T19:01:55.714942+03:00"
On my machine. Notice the timezone offset. That's also part of the standard. Z means UTC.
You can specify your own time format, provided it's the correct one. In this case, it should be yyyy-MM-ddTHH:mm:ss.fffZ. Notice the fff for milliseconds and HH for 24-hour.
The following code
var settings=new JsonSerializerSettings{DateFormatString ="yyyy-MM-ddTHH:mm:ss.fffZ"};
var json=JsonConvert.SerializeObject(DateTime.Now,settings);
returns
"2017-09-08T19:04:14.480Z"
The format string does not force a timezone translation. You can tell Json.NET to treat the time as Local or Utc through the DateTimeZoneHandling setting :
var settings=new JsonSerializerSettings{
DateFormatString ="yyyy-MM-ddTH:mm:ss.fffZ",
DateTimeZoneHandling=DateTimeZoneHandling.Utc};
var json=JsonConvert.SerializeObject(DateTime.Now,settings);
Returns :
"2017-09-08T16:08:19.290Z"
UPDATE
As Matt Johnson explains, Z is just a literal, while K generates either Z or an offset, depending on the DateTimeZoneHandling setting.
The format string yyyy-MM-ddTH:mm:ss.fffK with DateTimeZoneHandling.Utc :
var settings=new JsonSerializerSettings{
DateFormatString ="yyyy-MM-ddTH:mm:ss.fffK",
DateTimeZoneHandling=DateTimeZoneHandling.Utc};
var json=JsonConvert.SerializeObject(DateTime.Now,settings);
Will return :
2017-09-11T9:10:08.293Z
Changing to DateTimeZoneHandling.Utc will return
2017-09-11T12:15:12.862+03:00
Which, by the way is the default behaviour of Json.NET, apart from the forced millisecond precision.
Finally, .NET doesn't have a Date-only type yet. DateTime is used for both dates and date+time values. You can get the date part of a DateTime with the DateTime.Date property. You can retrieve the current date with DateTime.Today.
Time of day is represented by the Timespan type. You can extract the time of day from a DateTime value with DateTime.TimeOfDay. Timespan isn't strictly a time-of-day type as it can represent more than 24 hours.
What was that yet?
Support for explicit Date, TimeOfDay is comming through the CoreFX Lab project. This contains "experimental" features that are extremely likely to appear in the .NET Runtime like UTF8 support, Date, String, Channles. Some of these already appear as separate NuGet packages.
One can use the System.Time classes already, either by copying the code or adding them through the experimental NuGet source
Get current universaltime to json date time format and vice versa:
DateTime currentDateTime = DateTime.Now.ToUniversalTime();
var jsonDateTime = GetJSONFromUserDateTime(currentDateTime);
DateTime getDateTime = GetUserDateTimeFromJSON(jsonDateTime);
Here are both methods:
/// <summary>
/// Convert UserDateTime({9/7/2018 8:37:20 AM}) to JSON datetime(1536309440373) format
/// </summary>
/// <param name="givenDateTime"></param>
/// <returns></returns>
public static string GetJSONFromUserDateTime(DateTime givenDateTime)
{
string jsonDateTime = string.Empty;
if (givenDateTime != null)
{
JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
};
jsonDateTime = JsonConvert.SerializeObject(givenDateTime, microsoftDateFormatSettings);
jsonDateTime = jsonDateTime.Replace("\"\\/Date(", "").Replace(")\\/\"", "");
}
return jsonDateTime;
}
/// <summary>
/// Convert JSON datetime(1536309440373) to user datetime({9/7/2018 8:37:20 AM})
/// </summary>
/// <param name="jsonDateTime"></param>
/// <returns></returns>
public static dynamic GetUserDateTimeFromJSON(string jsonDateTime)
{
dynamic userDateTime = null;
if (!string.IsNullOrEmpty(jsonDateTime))
{
JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
};
userDateTime = JsonConvert.DeserializeObject("\"\\/Date(" + jsonDateTime + ")\\/\"", microsoftDateFormatSettings);
}
return userDateTime;
}
If, like Willie Esteche you wish to convert a number that is too low, you have probably got a Unix Date Time value. His solution does indeed work, but as of .Net Framework 4.6 there is an easier way to do things.
Given a value of 1500013000, first you convert this to a DateTimeOffset with the FromUnixTimeSeconds() method, then simply grab the DateTime component.
DateTime dt = DateTimeOffset.FromUnixTimeSeconds(1500013000).UtcDateTime;
Conversion back (assuming UTC) is performed like so:
long Udt = new DateTimeOffset(dt,TimeSpan.Zero).ToUnixTimeSeconds();
In my case, i using this config in vb.net, it's so easy translate to c #
settings.NullValueHandling = NullValueHandling.Ignore
settings.DateTimeZoneHandling = DateTimeZoneHandling.Local
BE = JsonConvert.DeserializeObject(Of EN_BE)(str, settings)
I get this format date from laravel API
2020-08-02T01:41:05.000000Z
and i convert to correct value same to database
2020-08-01 20:41:05
You can try this:
DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");

json Deserialization changes date

Hey I'm getting diffrent date after deserialization.
before the date is 30.03.2017, and after the date is 29.03.2017.
before
after
Json string (stam value):
[{"a_id":1,"auctionname":"computer","deadLine":"\/Date(1490821200000)\/"},{"a_id":2,"auctionname":"keyboard","deadLine":"\/Date(1490821200000)\/"},{"a_id":3,"auctionname":"mouse","deadLine":"\/Date(1490821200000)\/"}]
my code:
[Test]
public void GetAuctionsByJson_works()
{
Mock<IAuctionRespository> mockAuction = new Mock<IAuctionRespository>();
mockAuction.Setup(m => m.Auctions).Returns(new Auction[]
{
new Auction { a_id=1, auctionname="computer", deadLine=DateTime.Today},
new Auction { a_id=2, auctionname="keyboard", deadLine=DateTime.Today},
new Auction { a_id=3, auctionname="mouse", deadLine=DateTime.Today}
}.AsQueryable());
CustomerController controller = new CustomerController(mockAuction.Object);
var actual = controller.GetAuctionsByJson() as JsonResult;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string stam = serializer.Serialize(actual.Data);
List<Auction> result = serializer.Deserialize<List<Auction>>(serializer.Serialize(actual.Data));
//List<Auction> result = ser.ReadObject(actual);// as List<Auction>; //null --> decirialized
}
There are multiple issues.
First, the format \/Date(1490821200000)\/ isn't used anymore. It was used in the early 2000s when there was no defacto standard to represen time in AJAX calls. The number is an escaped number of ticks in UTC. The defacto standard is ISO8601, 2017-03-30T00:00:00Z.
Second JavascriptSerializer isn't used anymore. It's been replaced by Json.NET even in ASP.NET Web API. I'm not sure if it understands ISO8601 or not. It isn't used anyway, except in legacy code.
Finally, DateTime.Today returns the local time. DateTime.Today in a +3 timezone is 30/3/2017 12:00:00 am but 29/3/2017 09:00:00 pmin UTC. Its .Kind property is Local. Even Json.NET would serialize this as 2017-03-30T00:00:00+03:00
To get the current date in UTC, one should use DateTime.UtcNow.Date. This has a Kind value of Utc. Json.NET will serialize this as 2017-03-30T00:00:00Z
Try changind all calls to
DateTime.Today
with
DateTime.UtcNow.Date

.net DateTime Serialization Deserialization bug

If you serialize and deserialize a DateTime using embedded .net JavaScriptSerializer, you get two different dates if you are in UTC+something !
Example (suppose you are in UTC+2 like I am now)
JavaScriptSerializer myJson = new JavaScriptSerializer();
DateTime myDate = DateTime.Now; //suppose 2016-03-29 16:12:00
strSerialized = myJson.Serialize(myDate);
//DO WHAT YOU NEED WITH IT...
DateTime myDateDes = myJson.Deserialize<DateTime>(strSerialized);
Label1.Text=myDateDes.ToString();//it gives you 2016-03-29 14:12:00 ! WRONG! IT's in UTC+0 ! Has 2 HOURS less !!!
So, when you get the deserialized date, it'll give you the UTC+0 value by default...!!
This is different from JavaScriptSerializer UTC DateTime issues because that article describes the difference in deserialization of different datetime data types, and provides a solution (.UtcDateTime) that doesn't fix the problem. In fact, trying to deserialize with .utcDateTime a serialized DateTime always gives you the wrong UTC+0 date...
There are two different solutions: either use ToLocalTime() when you deserialize OR use the Newtonsoft.Json.
So the same code, "fixed", in the first case should be:
JavaScriptSerializer myJson = new JavaScriptSerializer();
DateTime myDate = DateTime.Now; //suppose 2016-03-29 16:12:00
strSerialized = myJson.Serialize(myDate);
//DO WHAT YOU NEED WITH IT...
DateTime myDateDes = myJson.Deserialize<DateTime>(strSerialized).ToLocalTime();
Label1.Text=myDateDes.ToString();//it gives you 2016-03-29 16:12:00 !!! CORRECT !
Otherwise, using Newtonsoft.Json (you first need to install it from nuGet, then add a "using Newtonsoft.Json" at the top), and use it like this:
DateTime myDate = DateTime.Now; //suppose 2016-03-29 16:12:00
strSerialized = JsonConvert.SerializeObject(myDate);
//DO WHAT YOU NEED WITH IT...
DateTime myDateDes = JsonConvert.DeserializeObject<DateTime>(strSerialized);
Label1.Text=myDateDes.ToString();//NO need to convert to LocalTime... it already gives you 2016-03-29 16:12:00 !!! CORRECT !
I hope this will be useful for someone else... I googled a lot and found nothing about this problem that only happens with Microsoft serializer...

Json.Net cannot deserialize DateTime.MinValue

I've tried deserializing a Json string containing DateTime.MinValue in every conceivable way, but when the set method gets called on my object. The date always gets changed from -01-01-01- to -01-01-02-.
The Json being parsed clearly contains
"inception_date": "0001-01-01T00:00:00+00:00"
I then call JsonConvert on it:
return JsonConvert.DeserializeObject<T>(json, deserializerSettings);
Where T is a basic struct that contains a property: DateTime inception_date { get; set; } property. The deserializer settings are as follows:
deserializerSettings = new JsonSerializerSettings()
{
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateParseHandling = Newtonsoft.Json.DateParseHandling.None,
DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc
};
Yet somewhere in the bowels of Newtonsoft.Json.dll, the above time gets converted to the following jObject.
"inception_date": "0001-01-02T00:00:00Z"
I have no way of stepping into their code, but by the damage is done before my code sees another call. ReadJson in the JsonConverter calls serializer.Populate(jObject.CreateReader(), target); where target is an instance of my class T, and jObject has somehow been rendered with the above incorrect date.
Can anyone figure out why this is happening or how I can prevent it? The jObject seems to be getting created in a way that is ignoring my serializer settings, which explicitly say not to screw with the date string (DateParseHandling.None).
I've taken screen shots to illustrate exactly where Newtonsoft's JsonConvert method seems to have lost a vital configuration value.
As you can see, this is the point in the code where I call JsonConvert:
The dateParseHandling value is set to None, and that's how it should be for this to work.
At this next step, I've jumped a few internal Newtonsoft calls and landed in a generic implementation of the JsonConverter which I borrowed from an accepted reference implementation to be able to see what was going on. The JsonReader passed in suddenly has lost that dateParseHandling value:
Because of this value being switched back to DateTime - the internal workings of the jObject try to represent this as an internal localized DateTime, which underflows because my timezone is negative, and we're already representing the minimum DateTime value, resulting in the conversion back to UTC adding a full day.
Try:
deserializerSettings = new JsonSerializerSettings()
{
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateParseHandling = Newtonsoft.Json.DateParseHandling.DateTimeOffset
}
This resulted in me getting 1/1/0001 12:00:00 AM instead of 1/2/0001 12:00:00 AM
Here is my test code (written in LINQPad)
void Main()
{
var deserializerSettings = new JsonSerializerSettings()
{
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateParseHandling = Newtonsoft.Json.DateParseHandling.None,
DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc
};
var json = "{\"inception_date\": \"0001-01-01T00:00:00+00:00\"}";
var parsedObj = JsonConvert.DeserializeObject<TestClass>(json, deserializerSettings);
Console.WriteLine(parsedObj);
deserializerSettings = new JsonSerializerSettings()
{
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateParseHandling = Newtonsoft.Json.DateParseHandling.DateTimeOffset
};
parsedObj = JsonConvert.DeserializeObject<TestClass>(json, deserializerSettings);
Console.WriteLine(parsedObj);
}
public class TestClass
{
public DateTime inception_date {get;set;}
}
Outputs:

Categories

Resources