Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse a TimeSpan value in Newtonsoft JSON

I'd like parse JSON string and use the token.Type property to detect values of type JTokenType.TimeSpan.

I can't work out how to express the TimeSpan in my input string, everything seems to be interpreted as JTokenType.String.

var timeSpanString = TimeSpan.FromHours(1).ToString();
testString = string.Format(@"{{""Value"": ""{0}"" }}", timeSpanString);
var statObject = JObject.Parse(testString);
JToken token = statObject["Value"];
var tokenValue = token.ToString();
var tokenType = token.Type; // JTokenType.String

I even tried:

JValue jValue = new JValue("test");
jValue.Value = TimeSpan.FromHours(1);
bool isTimeSpan = jValue.Type == JTokenType.TimeSpan; // true!
testString = string.Format(@"{{""Value"": ""{0}"" }}", jValue.Value);
var statObject = JObject.Parse(testString);
JToken token = statObject["Value"];
var tokenValue = token.ToString();
var tokenType = token.Type; // JTokenType.String

Which at least produces a JValue object of tokenType JTokenType.TimeSpan, but still shows up as a JTokenType.String when I parse it.

This works perfectly for DateTime objects. How can I express the input string such that the parsed value type is JTokenType.TimeSpan ?

like image 406
s d Avatar asked Feb 18 '23 10:02

s d


2 Answers

Based on what I've seen while using JSON.NET for a while now, you will never, with the default settings, parse a string and retrieve a token with type JTokenType.TimeSpan (same for some other types as well, such as Guid or Uri). I have a pretty good guess of why this is the case (based on my experience working a few years ago with the DataContractJsonSerializer).

Basically, it's a matter of how much information the parser can retrieve out of the input. JSON is a very simple syntax which only knows about numbers, boolean and strings (in addition to arrays and objects). Many CLR types don't have a native JSON type (Uri, DateTime, DateTimeOffset, TimeSpan, and so on), so when any JSON parser is reading the data, it will try to use the best match.

If you're deserializing the JSON string into a CLR data type, then the serializer has some additional information that it can use to disambiguate what a JSON string maps to - the type of the field / property that value is being deserialized to. However, when you're deserializing a JSON data to a JToken object graph, there's no additional information, and JSON.NET has to choose one type. The most natural type to deserialize a JSON string is, well, a CLR string.

But why do dates are deserialized correctly as JTokenType.Date? IIRC, the JSON.NET reader has a special code for dates (controlled by the DateParseHandling enumeration), which tries to match the parsed strings to some predefined formats (either ISO 8601 or the old Microsoft ASP.NET AJAX format), and if it finds a string which match it, it will read it as a DateTime (or DateTimeOffset) instead of a string. I don't know whether it's possible to extend that behavior to also support TimeSpan or other types, but I wouldn't be surprised, since the extensibility in JSON.NET is quite good.

like image 140
carlosfigueira Avatar answered Feb 21 '23 16:02

carlosfigueira


If you are trying to parse a TimeSpan it needs to be surrounded in quotations: '"12:00:00"'

If you serialize a TimeSpan and look at the string result it looks like: "\"12:00:00\""

At least this worked for me using NewtonSoft.JsonConvert. The string in my DB "12:00:00" (including the quotes).

And using JsonConvert.DeserializeObject(dbString) returns fine.

like image 28
boylec1986 Avatar answered Feb 21 '23 18:02

boylec1986