VSO
VSO

Reputation: 12646

Change DateTimeOffset.Offset Property?

My end goal is to get universal time from client with NO offset - just UTC time. I try to accomplish this like so:

Javascript: (new Date()).toUTCString(), the output of which logs: Thu, 17 Mar 2016 15:13:23 GMT, which is exactly what I need.

Then I take it to server and try to convert it to DateTimeOffset:

string dateTimeOffsetPattern = "ddd, dd MMM yyyy HH:mm:ss 'GMT'"; 

DateTimeOffset clientLoginTime = DateTimeOffset.ParseExact
    (timeStringFromClient, dateTimeOffsetPattern, CultureInfo.InvariantCulture);

Which results in:

3/17/2016 3:13:23 PM -04:00 

Somehow it adjusts the time for my local (Eastern) offset. I do NOT want this to happen, I want it to just return the UTC time, like so:

3/17/2016 3:13:23 PM +00:00

P.S. I did just ask another question about this, and I apologize, since I feel like it should be easy enough, but I don't get it. This should be really simple, but it looks like offset doesn't have a setter (unless I am completely missing some C# basics as usual):

public TimeSpan Offset { get; }

Upvotes: 7

Views: 13713

Answers (3)

Korayem
Korayem

Reputation: 12497

I would parse from JS normally, then do the following:

  • Strip OffSet from DateTimeOffset by returning DateTime
  • Set OffSetby instantiating another DateTimeOffset having TimeSpan set to ZERO.

In your case:

var clientLoginTime = new DateTimeOffset(clientLoginTime.DateTime, TimeSpan.FromHours(0));

This can be easily converted into an extension method

public static DateTimeOffset SetOffset(this DateTimeOffset dto, int timeZoneDiff)
{
    return new DateTimeOffset(dto.DateTime, TimeSpan.FromHours(timeZoneDiff));
}

Upvotes: 5

Igor
Igor

Reputation: 62238

From JavaScript (or any other client) you should send DateTimes using ISO8601 format which would be yyyy-MM-ddTHH-mm-ss.sssz. The Z indicates that the datetime instance is GMT (UTC). You can also change this to add + or - from GMT. You can do this using the JavaScript Date object using myDate.toISOString()

When creating your WebAPI model(s) you can then use either a DateTime or DateTimeOffset types directly. The JSON.NET serializer for Web API will automatically deserialize the sent ISO8601 datetime string to the correct DateTime or DateTimeOffset type (depending on which one you are using). This means that you do not have to do any manuall parsing in your code which is good. (Imagine if you had to send everything as string and parse everything manually in all your methods?).

So you can now have a method

public async Task<IHttpActionResult> GetRecords(DateTimeOffset? startFrom)

And the startFrom will automatically be populated based on the sent ISO8601 formatted DateTime string.

Finally, the last and most import reason to do this is that your clients will probably not all use the same locale. You could have a user that has their browser set to Spanish so .toUTCString() will not yield an English string or possibly even a string with mm/dd but the reverse (like most countries other than the USA).

Long story short for WebAPI

  • Use ISO8601 from/to client.
  • Use DateTimeOffset or DateTime instances directly in your model (no parsing).

Upvotes: 2

Dave Zych
Dave Zych

Reputation: 21887

There's an overload of ParseExact where you can specify a DateTimeStyles. One of the values of DateTimeValues is AssumeUniversal, which says:

If format does not require that input contain an offset value, the returned DateTimeOffset object is given the UTC offset (+00:00).

which basically means "don't assume it's local, assume it's universal." Assuming local is the default, which is why you're seeing the result you are in that it's adjusting to local. Specifying AssumeUniversal should parse it the way you want.

DateTimeOffset clientLoginTime = DateTimeOffset.ParseExact
(timeStringFromClient, dateTimeOffsetPattern, CultureInfo.InvariantCulture, 
    DateTimeStyles.AssumeUniversal);

Upvotes: 7

Related Questions