Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should DateTime.UtcNow Have a Timezone Offset?

This (LINQPad snippet):

DateTime.Now.ToString("yyyy-MM-ddTHH:mm:sszzz").Dump();
DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:sszzz").Dump();

Returns:

2016-01-08T09:05:04-07:00 // Expected
2016-01-08T16:05:04-07:00 // Not what I expected

Given that the 2nd result is universal time, I expected it to return 2016-01-08T16:05:04-00:00 (timezone offset of zero).

Am I missing something or is this a bug?

like image 714
Anders Avatar asked Jan 08 '16 16:01

Anders


People also ask

Does DateTime include timezone?

A DateTime value defines a particular date and time. It includes a Kind property that provides limited information about the time zone to which that date and time belongs.

Is DateTimeOffset always UTC?

The main difference between it and the simpler DateTime type we all know and love is that it includes a time zone offset from UTC. Thus, it's always clear when looking at a DateTimeOffset what time is meant, whether UTC or local.

Should I use DateTime now or DateTime UtcNow?

Use DateTime. UtcNow when you want to store dates or use them for later calculations that way (in a client-server model) your calculations don't become confused by clients in different time zones from your server or from each other.

What is offset value in DateTime?

The DateTimeOffset structure includes a DateTime value, together with an Offset property that defines the difference between the current DateTimeOffset instance's date and time and Coordinated Universal Time (UTC).


1 Answers

I wanna combine Gusman's and Evan's comments and create some arguments against them if they let me. Let's take step by step..

Should DateTime.UtcNow have a timezone offset?

No matter what Kind it has (Local, Utc or Unspecified), a DateTime instance does not keep any UTC offset value. Period.

First of all, let's take a look at the The "zzz" format specifier documentation;

With DateTime values, the "zzz" custom format specifier represents the signed offset of the local operating system's time zone from UTC, measured in hours and minutes. It does not reflect the value of an instance's DateTime.Kind property. For this reason, the "zzz" format specifier is not recommended for use with DateTime values.

Based on first two bold sentences, both result generated by LINQPad is totally expected. You can get the same results (expect date and time parts of course) in Visual Studio as well.

Just run this code as "Start Without Debugging" (Ctrl + F5)

Console.WriteLine(DateTime.Now.ToString("yyyy-MM-ddTHH:mm:sszzz"));
Console.WriteLine(DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:sszzz"));

But what about when you run it as "Start Debugging" with (F5)?

There are two option in such a case which depends on your DateTimeInvalidLocalFormat in Managed Debugging Assistants is ticked or not. This sections is on the Debug menu, then click Exceptions.

enter image description here

If this option is ticked, you get an exception and it says;

A UTC DateTime is being converted to text in a format that is only correct for local times. This can happen when calling DateTime.ToString using the 'z' format specifier, which will include a local time zone offset in the output. In that case, either use the 'Z' format specifier, which designates a UTC time, or use the 'o' format string, which is the recommended way to persist a DateTime in text.

If this option is not ticked, you won't get any message and the result will be the same as LINQPad.

Given that the 2nd result is universal time, I expected it to return 2016-01-08T16:05:04-00:00 (timezone offset of zero).

As I explained, zzz format specifier does not behave like that for any DateTime instance.

But it behaves differently for a DateTimeOffset instance which is documented as;

With DateTimeOffset values, this format specifier represents the DateTimeOffset value's Offset from UTC in hours.

And DateTimeOffset.Now and DateTimeOffset.UtcNow are perfectly fits your expectation no matter you run in LINQPad or Visual Studio since they are documented as;

Now

A DateTimeOffset object whose date and time is the current local time and whose offset is the local time zone's offset from Coordinated Universal Time (UTC).

UtcNow

An object whose date and time is the current Coordinated Universal Time (UTC) and whose offset is TimeSpan.Zero.

Console.WriteLine(DateTimeOffset.Now.ToString("yyyy-MM-ddTHH:mm:sszzz"));
Console.WriteLine(DateTimeOffset.UtcNow.ToString("yyyy-MM-ddTHH:mm:sszzz"));

would generate

2016-01-08T09:05:04-07:00
2016-01-08T16:05:04-00:00

Tl;dr I think this is not a bug. LINQPad generates the right results exactly what it should be. In Visual Studio, you might get an exception if that option is ticked or not in debugging mode.

like image 78
Soner Gönül Avatar answered Oct 13 '22 15:10

Soner Gönül