Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RestSharp converts Datetimes to UTC

Tags:

c#

restsharp

I have following problem

I'm using RestSharp for accessing my API. But when I'm sending a DateTime it seems to be converted to UTC. I'm sending '10.06.1991 00:00' and the API gets '09.06.1991 22:00'

So, I would always need to add 2 hours when my API gets a DateTime-object?

I checked the JSON RestSharp sends to the API.

public class Test
{
    public int IntProperty {get;set;}
    public string StringProperty {get;set;}
    public DateTime DateTimeProperty {get;set;}
}

My object is

Test t = new Test{ IntProperty=3, StringProperty="string", DateTimeProperty=new DateTime(1991,06,10) }

when I'm sending the object via RestSharp, the JSON my API receives is

{
    "IntProperty":3,
    "StringProperty":"string",
    "DateTimeProperty":"09.06.1991 22:00:00"
}

Any idea what I could do? Thanks

like image 423
its_time_for_weekend Avatar asked Jul 20 '17 09:07

its_time_for_weekend


2 Answers

It's not your API that receives wrong data, it's your client that sends "wrong" data. I got the same problem with my API. No, it's correct data but converted to UTC.

The exact problem is described here: https://github.com/restsharp/RestSharp/issues/834

So, don't add 2 hours to each DateTime you get it in your API. You would perhaps change correct data when another client sends unconverted dates.

  1. You could check, whether on GET you receive the right date. Maybe RestSharp is converting that "wrong" datetime back to 10.06.1991 00:00 - maybe you are okay with it
  2. if you want the database to not contain UTC but the data you original wanted to send, don't use the default serializer, use JSON.Net (http://www.newtonsoft.com/json). It won't convert to UTC and sends the original DateTime.

Here is one really good example on how to implement: http://bytefish.de/blog/restsharp_custom_json_serializer/

  • you write a custom class that implements ISerializer and IDeserializer
  • in serialize you call JSON.Net Serialize while in deserialize you call JSON.Net Deserialize

  • you just need to add a handler to your RestClient like this: (I'm using the static Default-instance described in the mentioned blog)

my client looks like:

private readonly RestClient _client;

public RestApiClient(string apiAdress)
{
    _client = new RestClient(apiAdress);
    _client.AddHandler("application/json", () => NewtonsoftJsonSerializer.Default);
}

and in requests you can set the JsonSerializer:

 IRestRequest restRequest = 
        new RestRequest(request.GetRestfulUrl(), request.Method) {
            RequestFormat = request.DataFormat, 
            JsonSerializer = NewtonsoftJsonSerializer.Default 
        };
like image 158
Matthias Burger Avatar answered Nov 12 '22 02:11

Matthias Burger


I guess it's because your DateTime objects have DateTime.Kind property equals to DateTimeKind.Unspecified - it breaks all conversions between local and utc kinds. I mean some tool assumes that your DateTime is in Utc when it isn't really.

So just don't fight with the tools which have to guess the right kind of your DateTimes in the middle between you and your client. Just use UTC everywhere and convert to local only to show it to user.

Or, even better, use DateTimeOffset which is more suitable to deal with multizone times.. or even use Jon Skeet's NodaTime library which is a swiss knife for any time-related work (although, maybe it's an overkill for your case).

UPD. To answer the question from @Matthias Burger in comments below:

How would you work with dates like date of birth? I think "10.06.1991" could be a birthday. Means, in UTC his birthday were different than GMT - wouldn't it?

As always - it depends :)

As time is a tricky thing, you should be careful - and there is a great article from the Jon Skeet's blog about joys of date/time arithmetic. I know it's not a real answer, honestly, but there're too much different possible problem cases - do we need to compare dates, are they in the same calendar, do we assume that all people were born at midnight in local time zone and etc.

In already mentioned NodaTime there's a concept of global and local instants (look at it's concepts page). I think for the most simple cases when we need to just store and show birthdays LocalDate (local date instant) is enough. Even DateTime is enough if you store local date and fixate the same time zone for all (so it'll be like you don't use time zone at all).

P.S. Btw, don't know if the last question was a check or not, but UTC is a standard and GMT is a time zone ;)

like image 2
pkuderov Avatar answered Nov 12 '22 01:11

pkuderov