Read date from JObject JSON.Net - c#

I want to dynamically read json. I have everything working but date. So I have
JObject obj = JObject.Load(reader);
data.location= (obj["duration"].Value<double>());
data.deviceID = (obj["deviceID"].Value<string>());
data.reason= (obj["reason"].Value<string>());
data.id= (obj["id"].Value<string>());
// data.startTime=(obj["startTime"].Value<DateTime>());
string start = (string)obj.SelectToken("startTime");
In quickwatch the date looks like
so I tried date time with no luck. If i can get the string value I found a different stackoverflow post that used this for a solution. However I can not read it in a good manner yet
private DateTime TryParseIso8601(string s)
{
string format = s.EndsWith("Z") ? "yyyy-MM-ddTHH:mm:ssZ" : "yyyy-MM-ddTHH:mm:sszzz";
DateTime date = new DateTime();
DateTime.TryParseExact(s, format, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out date);
return date;
}
Per comment, the exception generate by
data.startTime = (obj["startTime"].Value<DateTime>());
is

You can use the SelectToken to read the date.
var jToken = obj.SelectToken("startTime.$date");
var date = jToken.Value<DateTime>();
Check this live fiddle - https://dotnetfiddle.net/9o4FJt
Sample Code:
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
var jsonString = "{\"startTime\" : { \"$date\" : \"2018-03-19T19:38:02.929Z\"} }";
var jObj = JsonConvert.DeserializeObject<JObject>(jsonString);
Console.WriteLine(jObj);
var jToken = jObj.SelectToken("startTime.$date");
Console.WriteLine(jToken.Value<DateTime>());
Console.WriteLine("Hello World");
}
}

Related

How to avoid JObject.Parse parsing a DateTime, and instead just get the raw string?

I have a JSON data like below, when I read the DateTime tag, it is internally converted to {2/11/2022 6:56:17 AM}. I need data to be read in the string format, same as data available in the JSON
Code Snippet:
JObject jsonObject = JObject.Parse(jsonText);
var dateTime = jsonObject["LastModified"]["DateTime"]; // output = {2/11/2022 6:56:17 AM}, but i need "2022-02-11T06:56:17.143Z".
{"LastModified": {
"Username": "Philips Administrator",
"DateTime": "2022-02-11T06:56:17.143Z"
}
}
As others point out a DateTime has no format. When you convert it to a string you can format it however you like. If you really, really want to treat it as a string, you can do as Jon Skeet suggests:
var jsonText = #"{""LastModified"": {
""Username"": ""Philips Administrator"",
""DateTime"": ""2022-02-11T06:56:17.143Z""
}
}";
var settings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None
};
JObject jsonObject = (JObject)JsonConvert.DeserializeObject(jsonText, settings);
var dateTime = jsonObject["LastModified"]["DateTime"];
It also works with dates like "932 AD, a little before lunch time".

Cannot deserialize JSON with both UTC and non UTC formatted datetimes

I am reading in JSON from an external API. The datetime values are formatted differently for some reason and I cant get it to automatically deserialize into my object using Newtonsoft.Json.
For example, suppose the following is my JSON (the only diff in the two datetime values is the first one ends in 'Z' and the second does not):
string json = "{ \"DateTime1\" : \"20131101T000000Z\", \"DateTime2\" : \"20131101T000000\" }";
Then I need to parse the 2 datetime fields into an object containing DateTime1 and DateTime2 properties like this:
class Foo
{
public DateTime DateTime1 { get; set; }
public DateTime DateTime2 { get; set; }
}
My deserialization code looks like this:
var format = "yyyyMMddThhmmssZ"; // your datetime format
var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = format };
JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
serializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
serializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
serializerSettings.DateParseHandling = DateParseHandling.DateTimeOffset;
string json = "{ \"DateTime1\" : \"20131101T000000Z\", \"DateTime2\" : \"20131101T000000\" }";
try
{
var serializer = JsonSerializer.Create(serializerSettings);
var o3 = JsonConvert.DeserializeObject<Foo>(json, dateTimeConverter);
}
catch(Exception ex)
{
var x = ex.Message.ToString();
}
return;
Running the code above gives me:
String was not recognized as a valid DateTime
Any help would be greatly appreciated!
Your datetime format string for IsoDateTimeConverter doesn't look correct, try to update it per following
var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyyMMddTHHmmssK" };
According to Custom date and time format strings,
K format specifier is used for time zone information, there is no Z format specifier

How to use date format as constant in C#?

I'm using "yyyy-MM-dd" several time in the code for date formatting
For example :
var targetdate = Date.ToString("yyyy-MM-dd");
Is it possible to declare the format as constant, so that use of the code again and again can be avoided
Use an extension method without declare any format again and again like this:
public static class DateExtension
{
public static string ToStandardString(this DateTime value)
{
return value.ToString(
"yyyy-MM-dd",
System.Globalization.CultureInfo.InvariantCulture);
}
}
So you use it in this way
var targetdate = Date.ToStandardString();
Use this as
const string dateFormat = "yyyy-MM-dd";
//Use
var targetdate = Date.ToString(dateFormat);
OR
//for public scope
public static readonly string DateFormat = "yyyy-MM-dd";
//Use
var targetdate = Date.ToString(DateFormat);
//from outside the class, you have to use in this way
var targetdate = Date.ToString(ClassName.DateFormat);
Another option that you can do is use the DateTimeFormatInfo overload on .ToString(...) rather than the string overload.
public static readonly System.Globalization.DateTimeFormatInfo MyDateTimeFormatInfo
= new System.Globalization.DateTimeFormatInfo()
{
ShortDatePattern = "yyyy-MM-dd",
LongTimePattern = "",
};
Now you can do var targetdate = DateTime.Now.ToString(MyDateTimeFormatInfo); which is much the same as using string, but you have a lot more control over many other formatting properties.

DRY string formatting

What is an elegant way to pull out common formats (e.g. datetime) for string.format into accessible constants?
Ideally I would like to do something like the following, but I get the below error when I try to use this code.
var now = DateTime.Now;
var format = "yyyy-MM-dd";
Console.WriteLine(string.Format("The date is {1:{0}}", format, now));
[System.FormatException: Input string was not in a correct format.]
at Program.Main(): line 9
The reasoning behind this is that certain API's require a specific datetime format. I would like to be able to reference a single place to get that format, such that all or none of the calls will work.
I realize that the following will work, but it doesn't seem very elegant.
Console.WriteLine(string.Format("The date is {1:" + format + "}", format, now));
You could go an app constant route - a static class that holds your format strings.
namespace App.Framework {
public static class AppConstant {
public static readonly string DisplayDateShort = "MM/dd/yyyy";
}
}
As far as your example goes, it's kind of flawed; you want to call ToString() on your DateTime value.
Console.WriteLine(now.ToString(AppConstant.DisplayDateShort));
You can find all the used format strings under DateTimeFormatInfo.CurrentInfo.GetAllDateTimePatterns().
Afterwards you can individually try to parse your input data with each value and see which on returns true (see: DateTime.TryParseExact()).
Console.WriteLine (DateTimeFormatInfo.CurrentInfo.GetAllDateTimePatterns());
Sample code:
void Main()
{
var now = DateTime.Now.ToString();
foreach(var format in DateTimeFormatInfo.CurrentInfo.GetAllDateTimePatterns()){
DateTime result;
if(DateTime.TryParseExact(now, format, CultureInfo.CurrentCulture, DateTimeStyles.None, out result)){
Console.WriteLine(string.Format("The date is {0}, the format is: {1}", result, format));
}
}
}
You could consider pushing the format into an extension method that could be consumed as needed, i.e.:
public static class DateExt
{
public static string FormatAsSomething( this DateTime dt )
{
string format = "yyyy-MM-dd";
string result = dt.ToString( format );
return result;
}
}
And then:
var now = DateTime.Now;
Console.WriteLine( "The date is {0}", now.FormatAsSomething() );
Whenever the format needs to be updated, simply update the extension method.
You can use custom format provider for DateTime values:
static void Main(string[] args)
{
var now = DateTime.Now;
var str = string.Format(new MyDateFormatter(), "The date is {0}", now);
Console.WriteLine(str);
MyDateFormatter.DefaultDateFormat = "dd-MM-yyyy HH:mm";
str = string.Format(new MyDateFormatter(), "The date is {0}", now);
Console.WriteLine(str);
}
public class MyDateFormatter: IFormatProvider, ICustomFormatter
{
public static string DefaultDateFormat = "yyyy-MM-dd";
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
return null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
// Check whether this is an appropriate callback
if (!this.Equals(formatProvider))
return null;
var argFormat = "{0:" + (arg is DateTime ? DefaultDateFormat : string.Empty) + "}";
return string.Format(argFormat, arg);
}
}

Parsing a JSON date info into a C# DateTime

I have a a WCF service that returns a CLR object. This object is defined as follows:
[DataContract]
public class Person
{
[DataMember]
public string FullName
{
get { return fullName; }
set { id = fullName; }
}
private string fullName = string.Empty;
[DataMember]
public DateTime BirthDate
{
get { return birthDate; }
set { birthDate = value; }
}
}
Instances of this object are being created and returned from my WCF service. This service looks like the following:
[OperationContract]
[WebGet(UriTemplate = "/GetPersonByID/{id}", ResponseFormat = WebMessageFormat.Json)]
public Person GetPersonByID(string id)
{
Person person = FindPersonByID(id);
return person;
}
When I get the response back in my application, I can successfully extract the FullName value. However, I haven't successfully been able to convert the BirthDate to a C# DateTime object in my client application. When converted to a string, the BirthDate looks something like this:
\/Date(1297367252340-0500)\/
How do I get that into a C# DateTime instance?
Thanks!
Here are two options:
You can use the Deserialize method from System.Web.Script.Serialization.JavaScriptSerializer (in System.Web.Extensions.dll).
or you could use the ReadObject method from System.Runtime.Serialization.Json.DataContractJsonSerializer (in System.Runtime.Serialization.dll or in .NET 3.5 in System.ServiceModel.Web.dll).
Make sure that your date is wrapped in quotes like:
string dateString = #"""\/Date(1297367252340-0500)\/""";
The reason the date is in this weird format is that DateTime is a primitive in WCF. Unfortunately, there is no universally standardized format for serializing dates and times in JSON -- various frameworks use various string formats.
The dilemma is that WCF needs to natively understand that a particular string over the wire is indeed a DateTime, not just another plain vanilla JSON string. Hence the strange format. As soon as DataContractJsonSerializer encounters a date starting with \/Date, it starts trying to parse it as a date.
Now, to answer your question, when you are sending a DateTime over the wire, it depends on if you're using a web browser client, a Silverlight client, or a WCF client.
A WCF client or a Silverlight 2+ client should NOT have problems with this -- they should auto-use the DataContractJsoNSerializer, and if they're not using it, you can plug in DCJS manually.
If you are using a web client, you can include the .js file that ships with ASP. NET AJAX (I believe it is called MicrosoftAspNetAjax.js, or MicrosoftAjax.cs, though the name may have changed). Its deserialize function will auto-parse these dates as well.
Hope that helps!
Well, lately I had to work on an Android Mobile (Xamarin Studio) app project where I was unable to use Newtonsoft Json (Json.NET) due to errors thrown during deployment to this specific device version (Android API 16 Version 4.2.1).
Luckly I found an alternative library for json (System.Json). However this library does not have a way of casting JSON date to C# DateTime implicitly.
I have created the following two functions for nullable date and date conversions from a string json date(i.e /Date(1389435240000+0000)/)
The code can be improved but it does the job for now
public static DateTime? ConvertToNallableDate(string date)
{
DateTime? val = null;
/* /Date(1389435240000+0000)/*/
try{
if(!string.IsNullOrEmpty(date))
{
date = date.Replace ("/Date(", string.Empty).Replace (")/", string.Empty);
int pIndex = date.IndexOf ("+");
if(pIndex < 0) pIndex = date.IndexOf("-");
long millisec = 0;
date = date.Remove (pIndex);
long.TryParse (date, out millisec);
System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo("en-GB");
DateTime newDate = DateTime.Parse ("1970,1,1", ci);
newDate = newDate.AddMilliseconds(millisec);
val = newDate == null ? (DateTime?)null : newDate;
}
}catch {
val = null;
}
return val;
}
public static DateTime ConvertToDate(string date)
{
DateTime val = new DateTime();
/*/Date(1389435240000+0000)/*/
try{
if(!string.IsNullOrEmpty(date))
{
date = date.Replace ("/Date(", string.Empty).Replace (")/", string.Empty);
int pIndex = date.IndexOf ("+");
if(pIndex < 0) pIndex = date.IndexOf("-");
long millisec = 0;
date = date.Remove (pIndex);
long.TryParse (date, out millisec);
System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo("en-GB");
DateTime newDate = DateTime.Parse ("1970,1,1", ci);
val = newDate.AddMilliseconds(millisec);
}
}catch {
val = new DateTime();
}
return val;
}
This solved my problem
using System.Web.Script.Serialization;
//code
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
DateTime ddate = json_serializer.Deserialize<DateTime>(#"""\/Date(1326038400000)\/""").ToLocalTime();

Categories

Resources