Keep same Datetime format while reading from JSON in C# - 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);

Related

String builder in c# json problem with \" [duplicate]

This question already has answers here:
C# to JSON serialization using JSON.Net
(2 answers)
Closed 2 months ago.
I created an exaple to demonstrate the problem. I am trying by string builder create a json but there is one problem when the Model.Code contains the \".
If the model value contains double quote json is not valid.
public class Model
{
public string Name { get; set; }
public string Code { get; set; }
}
List<Model> list = new List<Model>();
list.Add(new Model()
{
Name = "Test1",
Code = "124565123"
});
list.Add(new Model() {
Name = "Test2",
Code= "123 \"45"
});
list.Add(new Model()
{
Name = "Test3",
Code = "456"
});
var sb = new StringBuilder();
sb.Append($"\"item_name\":\"{list[0].Name}\",");
sb.Append($"\"item_id\":\"{list[0].Code}\",");
sb.Append($"\"item_name\":\"{list[1].Name}\",");
sb.Append($"\"item_id\":\"{list[1].Code}\",");
sb.Append($"\"item_name\":\"{list[2].Name}\",");
sb.Append($"\"item_id\":\"{list[2].Code}\",");
return sb.ToString();
Add reference to Newtonsoft Json.NET library and serialize the list to json
string json = JsonConvert.SerializeObject(list);
since you are using StringBuilder, " will be Considered as " in the String value just like below
"item_name":"Test1","item_id":"124565123","item_name":"Test2","item_id":"123 "45","item_name":"Test3","item_id":"456",
so , if you want to Convert it to Json , then Json will not Consider value with Double Quote In Between.
Moreover, backslash with double quote ' \" ' suppose to Escape Special Character while Converting to json
I am not sure that you want to Keep that special Character in you Json string If yes then In My Opinion you should try by placing double backslash \\" and Double Quote before your Special Character. and json will Accept it
ex.
\\"45

Change default DynamoDB .NET SDK behavior to store DateTime as Unix time

By default, DynamoDB converts .NET DateTime to a string type (S) and stores dates in ISO-8601 format. See supported data types. The problem is .NET captures 7 digits for ticks whereas ISO-8601 stores 3. So, if I were to store a DateTime, fetch the entity, and compare the .NET date to what is fetched (for example in a test), this will fail.
TimeOfDay comparisons:
15:28:21.4731507 (.NET)
15:28:21.473 (DynamoDB)
Another problem I see is the DynamoDB SDK will convert UTC to local time when items are being retrieved. See a reported issue with a workaround. The suggested fix does not work for me. The converter will successfully convert the date via ToUniversalTime(), but it seems the returned value is being ignored. Thus, I still get a local time.
I'd like to avoid storing dates in ISO-8601. I know that I can store the ticks as a long property in my entities. This eliminates both problems described above. The caveat is I won't be able to use a DateTime property type anywhere in my entities going forward.
This brings me to my question. Is it possible to override the default SDK behavior so that DateTime is stored as a number type (N) in DynamoDB?
To address the issue of truncated ticks, you can use the "o" date format string, which is the "round trip" date format, for this exact scenario. The GitHub example wasn't specifying a format in its ToEntry lambda, so I believe it was further truncating information when ToString() was then called without any format information.
You can modify the sample in GitHub like so:
public class CustomDateTimeConverter : IPropertyConverter
{
public DynamoDBEntry ToEntry(object value)
{
DateTime? dateTimeValue = value as DateTime?;
if (dateTimeValue == null)
{
throw new ArgumentOutOfRangeException();
}
string dateTimeString = dateTimeValue?.ToUniversalTime().ToString("o");
DynamoDBEntry entry = new Primitive
{
Value = dateTimeString,
};
return entry;
}
public object FromEntry(DynamoDBEntry entry)
{
Primitive primitive = entry as Primitive;
if (primitive == null || !(primitive.Value is string) || string.IsNullOrEmpty((string)primitive.Value))
{
throw new ArgumentOutOfRangeException();
}
string dateTimeString = primitive.Value as string;
DateTime dateTimeValue = DateTime.Parse(dateTimeString).ToUniversalTime();
return dateTimeValue;
}
}
Few things to note here:
We're calling ToString with "o" to get the round-trip format
We force to UniversalTime before we call ToString("o"); to get the "Z" format of the string instead of the offset format no matter if you pass a DateTimeKind.Local or DateTimeKind.Utc in.
We force to UniversalTime in FromEntry as well, since you seemed to want to use Utc. When comparing DateTime, it's always worth comparing .Kind as well.
We still add this to our context, as in the GitHub example:
context.ConverterCache.Add(typeof(DateTime), new CustomDateTimeConverter());
Note the impact that setting the output DateTimeKind has via this example:
var utcDate = DateTime.UtcNow;
// Create a book.
DimensionType myBookDimensions = new DimensionType()
{
Length = 8M,
Height = 11M,
Thickness = 0.5M,
};
Book utcBook = new Book
{
Id = 501,
Title = "UtcBook",
Isbn = "999-9999999999",
BookAuthors = new List<string> { "Author 1", "Author 2" },
Dimensions = myBookDimensions,
publishedOn = utcDate,
};
var localDate = DateTime.Now;
Book localBook = new Book
{
Id = 502,
Title = "Local Book",
Isbn = "999-1111",
BookAuthors = new List<string> { "Author 1", "Author 2" },
Dimensions = myBookDimensions,
publishedOn = localDate,
};
// Add the book to the DynamoDB table ProductCatalog.
await context.SaveAsync(utcBook);
await context.SaveAsync(localBook);
// Retrieve the book.
Book utcBookRetrieved = await context.LoadAsync<Book>(501);
Console.WriteLine(#$"Original: {utcDate.TimeOfDay}({utcDate.Kind}) => Saved: {
utcBookRetrieved.publishedOn.TimeOfDay}({utcBookRetrieved.publishedOn.Kind}). Equal? {
utcDate.TimeOfDay == utcBookRetrieved.publishedOn.TimeOfDay} ToUniversal() Equal? {
utcDate.ToUniversalTime().TimeOfDay == utcBookRetrieved.publishedOn.ToUniversalTime().TimeOfDay}");
Book localBookRetrieved = await context.LoadAsync<Book>(502);
Console.WriteLine(#$"Original: {localDate.TimeOfDay}({localDate.Kind}) => Saved: {
localBookRetrieved.publishedOn.TimeOfDay}({localBookRetrieved.publishedOn.Kind}). Equal? {
localDate.TimeOfDay == localBookRetrieved.publishedOn.TimeOfDay} ToUniversal() Equal? {
localDate.ToUniversalTime().TimeOfDay == localBookRetrieved.publishedOn.ToUniversalTime().TimeOfDay}");
This prints:
Original: 20:12:52.4810270(Utc) => Saved: 20:12:52.4810270(Utc). Equal? True ToUniversal() Equal? True
Original: 15:12:52.4812120(Local) => Saved: 20:12:52.4812120(Utc). Equal? False ToUniversal() Equal? True
You can also use this method to export ticks, instead. Just change the ToEntry/FromEntry to convert to the number ticks.

Json.Net messes up timezones for DateTimeOffset when serializing

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.

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

How to deserialize Json in a Json?

Here is my json returned by php web application:
{"subtotal":475,"tax":47.5,"discount_section":[{"amount":237.5,"name":"test prior for percentage discount
"}],"grand_total_incl_tax":332.5}
I use c# and json.net to decode the abvoe json
var cart = webClient.DownloadString("http://localhost/m1/pos_addToCart.php?pidstr=" + pid_str);
dynamic result = JObject.Parse(cart);
But there is an error on this line:
order_discount_section.Text = result.discount_section;
Error:
Cannot implicitly convert type 'Newtonsoft.Json.Linq.JToken' to 'string'
How to convert this json to String like:
Key1 = Value1
Key2 = Value2
Key3 = Value3
Based upon your supplied json discount_section is a map so it can't be expressed as a string. It's like trying to convert a dictionary to a string or an array to a string.
If you want it as a string representation then adding ToString() after the result.discount_section (i.e. result.discount_section.ToString()) should accomplish that.
Though I would suggest that you either store the data through placeholder values such as:
string name = result.discount_section[0].name (same with amount but float/decimal/double...).
Or if you wanted it as text have it as
text = "Name: " + result.discount_section[0].name
+ "Amount: " + result.discount_section[0].amount.ToString();`
Obviously using a stringbuilder or other tool would be better (such as string.format) but I'll leave that as an 'exercise' to you.
Edit:
The for loop for all of the results.
totalText = ""
for (i = 0; i < result.discount_section.length; i++) {
totalText += "Name: " + result.discount_section[i].name + "Amount: " + result.discount_section[i].amount.ToString() + "\n";
}
Obviously if you wanted an array of strings then you would just build an array then just use i as your string array index as well.
Json.NET provides a correct behaviour.
As from your example string, it can be seen, that discount_section is a json array, or JArray, descendant of JToken after parsing to JObject.
If you want to access inner member of this array, as name for example, you should call it as
order_discount_section.Text = result.discount_section[0].name;
If you want to write the full notation of discount_section as is, you should explicitly call ToString method:
order_discount_section.Text = result.discount_section.ToString();
Although, dealing with dynamics is not useful, while your working with separate service responsing in JSON. It will be better to define a single class, which will handle json values, so you could not only look what json is passing, but to work with it
You may consider working with objects and deserialize using JsonConvert.DeserializeObject. Example:
class Discount
{
public Decimal Amount { get; set; }
public String Name { get; set; }
}
class Response
{
public Decimal Subtotal { get; set; }
public Decimal Tax { get; set; }
public List<Discount> Discount_section { get; set; }
public Grand_total_incl_tax { get; set; }
}
var response = JsonConvert.DeserializeObject<Response>(cart);
This approach is good when object structure is relatively fixed and has the following advantages:
clear structure
relevant errors when you have a type mismatch (JSON -> property)
result.discount_section is collection. you can not set directly to string variable.
try this.
var result= JObject.Parse(cart);
dynamic[] discountSection = result["discount_section"].ToArray<dynamic>();
decimal amount = discountSection[0].amount;
decimal name = discountSection[0].name;
for dictionary
Dictionary<string,decimal> discountDictionary = discountSection.ToDictionary<dynamic, string, decimal>((d) => d.name, (d) => d.amount);

Categories