Proper Way to Convert JSON Date to .NET DateTime During Deserialization
I found a simple answer. In my javascript, I was serializing the data using the JavaScriptSerializer. After much googling, I found this article that shows how to serialize using JsonConvert that causes a more .NET-friendly DateTime to be used.
Old:
var specs = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.JobSpecEquipment))
Dates look like this: Date(1348017917565)
New:
var specs = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.JobSpecEquipment));
Dates look like this: 2012-09-18T21:27:31.1285861-04:00
So the problem was really how I was serializing in the first place. Once I used JsonConvert, deserialization on the back end simply worked.
Deserialize JSON Date to C# Object with DateTime Returning 01/01/0001
Add [JsonProperty("Start Date")]
above public DateTime StartDate { get; set; }
and similar above public DateTime EndDate { get; set; }
:
public class MyObject
{
public string Name { get; set; }
[JsonProperty("Start Date")]
public DateTime StartDate { get; set; }
[JsonProperty("End Date")]
public DateTime EndDate { get; set; }
}
The problem was that json property names ('Start Date') and class property names ('StartDate') were not the same so it defaulted to 01/01/0001.
This will work without the need for IsoDateTimeConverter
.
JSON Date and DateTime serialisation in c# & newtonsoft
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 uses 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
Newtonsoft Json converts datetime format when deserializing to string
So it turns out the problem was with a custom converter we are using for some outer classes that first parses the whole object to a JObject, and then does further deserialization from that JObject. I don't want to make too dramatic of changes to this custom converter as it may adversely affect the behavior of other parts of the codebase. So here is what I'm doing as a workaround.
First, I moved the date/time format string to a public constant:
public const string DefaultDateFormatString = "yyyy-MM-ddTHH:mm:ss.fffffffZ";
Then I modified the constructors on the class I was having problems with to explicitly set the date strings to my required format:
public class MyData
{
public MyData(string value, string startDate, string endDate)
{
this.Value = value;
this.StartDate = startDate;
this.EndDate = endDate;
}
[JsonConstructor]
public MyData(string value, DateTimeOffset startDate, DateTimeOffset endDate)
: this(
value,
startDate.ToString(JsonUtility.DefaultDateFormatString),
endDate.ToString(JsonUtility.DefaultDateFormatString))
{
}
public string Value { get; }
public string StartDate { get; }
public string EndDate { get; }
}
Deserializing JSON string to .NET DateTime in local Timezone adds two hours
The solution to the problem proved to be a simple one. Just assume all times are UTC. This fixes all issues in the conversion.
var foo = JsonConvert.DeserializeObject<CustomTime>(json, new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc
});
Parsing a JSON date into a C# DateTime
You need to manually wrap your string "programatically" in quotes to ensure that it properly formatted correctly:
string sa = @"""" + "/Date(1409202000000-0500 )/" + @"""";
DateTime dt = JsonConvert.DeserializeObject<DateTime>(sa);
If you need to call it multiple times (which it seems like you do), just move the wrapping responsibility to a method:
public string WrapStringInQuotes(string input)
{
return @"""" + input + @"""";
}
How to serialize JSON string containing date and time property using DataContractJsonSerializer?
In the case of having a constraint about adding third-party NuGet packages, why not trying to clone/download the package (i.e. Newtonsoft.JSON) from Github and add them directly to your project. So that you won't have any third-party dll your deployment (bin folder).
Please note that the latest versions of the Newtonsoft.JSON are implemented in .netcore and while your project is on .net framework 4, you have to download the compatible version. You can use the tags to find the best version to download.
Use JSON.NET to parse json date of format Date(epochTime-offset)
/Date(1445301615000-0700)/
That is meant to represent a UTC time of 2015-10-19 17:40:15
Sorry, that's incorrect. The UTC time is 2015-10-20 00:45:15
. Your value corresponds to the local time, in a time zone with a -07:00
offset at that instant.
In this screwy format, the timestamp portion is still based solely on UTC. The offset is extra information. It doesn't change the timestamp. You can give a different offset, or omit it entirely and it's still the same moment in time.
All of the following are equivalent, with regard to point-in-time.
/Date(1445301615000-0700)/
/Date(1445301615000)/
2015-10-20T00:40:15Z
2015-10-19T17:40:15-07:00
Notice that in in the ISO format, the offset does change the value, but in the MS format it does not.
It would be best if you did not use this format, as ISO8601 is a much saner choice for JSON. However if you're stuck with it, then it's best not to deserialize it to a DateTime
. Instead, use a DateTimeOffset
.
Consider:
string s = "\"/Date(1445301615000-0700)/\"";
DateTime dt = JsonConvert.DeserializeObject<DateTime>(s);
Console.WriteLine(dt.Kind); // Local
That's no good. basically, if there is any offset, it thinks it's your local time zone, which it might be, but it might not be.
string s = "\"/Date(1445301615000)/\"";
DateTime dt = JsonConvert.DeserializeObject<DateTime>(s);
Console.WriteLine(dt.Kind); // Utc
This is ok, but you've lost track of that local time.
string s = "\"/Date(1445301615000-0700)/\"";
DateTimeOffset dto = JsonConvert.DeserializeObject<DateTimeOffset>(s);
Console.WriteLine(dto); // 10/19/2015 5:40:15 PM -07:00
That's much better. And if you do indeed want a UTC DateTime
, then:
string s = "\"/Date(1445301615000-0700)/\"";
DateTimeOffset dto = JsonConvert.DeserializeObject<DateTimeOffset>(s);
DateTime utc = dto.UtcDateTime;
Console.WriteLine(utc); // 10/20/2015 12:40:15 AM
So the key lesson is, regardless of format, if there is time zone offset information present in the data, then deserialize to DateTimeOffset
. While using DateTime
might work in some cases, you are asking .NET to interpret the offset and apply default behavior, which often will not be the desired behavior.
Related Topics
Declare Properties to Ignore in Entities Interface (Ef Core)
Returning a File to View/Download in ASP.NET MVC
Validate Indian Phone Number With Optional +91 or 0 Preceeding 10 Digits
Use Latest Version of Internet Explorer in the Webbrowser Control
How to Use a Nuget Package Within a Powershell Script
Select Multiple Fields from List in Linq
Decrypt M3U8 Playlist Encrypted With Aes-128 Without Iv
Moq - Verify Exception Was Thrown
Instantiating an Iformfile from a Physical File
How to Upload a Excel File to SQL Database Table Using C# Windows Form Application
How to Secure the Asp.Net_Sessionid Cookie
How to Ignore First Two Columns of CSV File
How to Encrypt a Password Within Appsettings.Json for ASP.NET Core 2
How to Remove Windows Credentials
Get Properties and Values from Unknown Object
Generate C# Class from SQL Server Table Without Store Procedure