4

I have a ASP.Net Core service that uses Newtonsoft.Json library for working with JSON data. The sample JSON input has a string that holds a date value in ISO8601 format. However I am observing different date time value being returned for an equivalent date. Here is the sample code -

    var jsonString = @"{
        ""data"": {
            ""name"": ""John Doe"",
            ""dateOfBirth"": ""1990-05-25T15:54:49.119+00:00""
        }
    }";

    var jsonObj = JObject.Parse(jsonString);
    var person = jsonObj.ToObject<Person>();

    DateTime dateOfBirth = DateTime.Parse(person.Data.DateOfBirth);
    if (dateOfBirth.Kind != DateTimeKind.Utc)
    {
        dateOfBirth = dateOfBirth.ToUniversalTime();
    }
    Console.WriteLine("Date of birth is " + dateOfBirth.ToString("o"));

The Person class is like this -

class Person
{
    public PersonalData Data;
}

class PersonalData
{
    public  string Name { get; set; }
    public string DateOfBirth { get; set; }
}

If I provide ""dateOfBirth"": ""1990-05-25T15:54:49.119+00:00"", the output is -

Date of birth is 1990-05-25T15:54:49.0000000Z

If I provide ""dateOfBirth"": ""1990-05-25T15:54:49.119Z"", the output is -

Date of birth is 1990-05-25T10:24:49.0000000Z

As it can be seen, the output is different where as it should have been same. The callers can set any date time string in ISO8601 format.

Is there any way where this can be handled consistently?

tyrion
  • 714
  • 2
  • 7
  • 27
  • `if (dateOfBirth.Kind != DateTimeKind.Utc)` should be `if (dateOfBirth.Kind == DateTimeKind.Local)`. Otherwise you convert DateTimeKind.Unspecified to universal time, which means it interprets the kind as local. If it is Unspecifed, you should `DateTime.SpecifyKind(dateOfBirth, DateTimeKind.Utc)`. – Jesse de Wit Mar 05 '19 at 21:19

3 Answers3

4

This is because DateTime.Parse() takes into account the system time zone (of the computer you run this code)

The solution is here

   var jsonString = @"{
        ""data"": {
            ""name"": ""John Doe"",
            ""dateOfBirth"": ""1990-05-25T15:54:49.119+00:00""
        }
    }";
var jsonObj = JObject.Parse(jsonString);
var person = jsonObj.ToObject<Person>();

var dateTimeOffset = DateTimeOffset.Parse(person.Data.DateOfBirth, CultureInfo.InvariantCulture);
DateTime dateOfBirth = dateTimeOffset.UtcDateTime;
Console.WriteLine("Date of birth is " + dateOfBirth.ToString("o"));
Sunil Purushothaman
  • 8,435
  • 1
  • 22
  • 20
0

If you use DateTimeOffset it should fix your issue. Rather than trying to rewrite information that already exists I would point you to a couple of existing resources:

These uses for DateTimeOffset values are much more common than those for DateTime values. As a result, DateTimeOffset should be considered the default date and time type for application development.

From MSDN Development Guide

DateTime vs DateTimeOffset

Dan Siegel
  • 5,724
  • 2
  • 14
  • 28
  • I don't think the problem is with DateTime. The problem happens with Json.Net, which is doing Date Time conversion differently when string has "Z" suffix or "00:00" – tyrion May 26 '17 at 02:54
  • It gives correct result when string is ""1990-05-25T15:54:49.119+00:00"" – tyrion May 26 '17 at 02:56
0

I have tried using JsonConvert.DeserializeObject(jsonString) and got the expected output. Please check this fiddle

https://dotnetfiddle.net/uuZvab

Person person = JsonConvert.DeserializeObject<Person>(jsonString);
                DateTime dateOfBirth = DateTime.Parse(person.Data.DateOfBirth);
                if (dateOfBirth.Kind != DateTimeKind.Utc)
                {
                    dateOfBirth = dateOfBirth.ToUniversalTime();
                }
                Console.WriteLine("Date of birth is " + dateOfBirth.ToString("o"));
snehgin
  • 191
  • 1
  • 1
  • 8
  • In the example I had to do cook up the code to to do JObject.Parse() to get a JObject. However in my production code, its the asp.net framework code handing me the JObject which has date of birth property already populated. – tyrion May 26 '17 at 10:55
  • Should I do JObject.ToString() to pass in to JsonConvert.DeserializeObject method? – tyrion May 26 '17 at 10:57
  • think this would do the trick `string json = myJObject.ToString(Newtonsoft.Json.Formatting.None);` – snehgin May 29 '17 at 07:40