19
votes

I need to convert DateTime+TimeZoneInfo into DateTimeOffset.

How do I do this? I assume I have to pass TimeSpan but then I'm not sure if daylight saving times will be handled properly..

Thanks!

UPDATE

TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow, timeZone.BaseUtcOffset);

This code throws exception..

The UTC Offset for Utc DateTime instances must be 0.\r\nParameter name: offset

UPDATE 2

Sorry, I didn't realize that DateTimeOffset contains only offset, it doesn't contain actual zone information - so I'm accepting answer from @Dave as it is what I will be using..

4
Related question: stackoverflow.com/q/2532729/1583Oded
Use DateTime.Now, not DateTime.UtcNow.Oded
This is just illustration of the problem. My data source has all the dates marked as Utc. I need to convert them to different TimeZoneskatit
Don't use TimeZoneInfo - just create a new TimeSpan with all fields set to 0.Oded
@Oded O do not understand how I can do that. My goal is to get DateTimeOffset with PROPER time zone inside of it. My understanding is that DateTimeOffset contains UTC + TimeZone and this is exactly how I want it. This data will be later used to display times on UIkatit

4 Answers

20
votes

You should be about to get the difference between DateTime.UtcNow and DateTime.Now

var now = DateTime.Now;
var utcNow = now.ToUniversalTime();
var ts = utcNow - now;

If you are saving the offset, it is usually beneficial to save all dates in UTC (especially in a db) so you won't have to deal with offsets. You simply convert them before displaying but do all calculations in UTC.

Edit: If you have a TimeZone object, you can convert a UTC date to the local time for that time zone.

TimeZone.CurrentTimeZone.ToLocalTime()

OR

DateTime dt = TimeZoneInfo.ConvertTimeFromUtc()

Here's some sample code that will list a date in all timezones.

var dt = new DateTime(2011, 5, 21, 11, 0, 0);
foreach (var tzi in TimeZoneInfo.GetSystemTimeZones())
{
    Console.WriteLine(string.Format("Time in {0} is {1}", tzi.DisplayName, TimeZoneInfo.ConvertTimeFromUtc(dt, tzi)));
}
7
votes

TimeZoneInfo has a BaseUtcOffset property that is a TimeSpan representing the offset.

This is the offset that the DateTimeOffset constructors expects:

var myDTOffset = new DateTimeOffset(myDatetime, mytzInfo.BaseUtcOffset);
4
votes

I think there may be an easier solution to eliminate the error. You tried:

TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow, timeZone.BaseUtcOffset);

DateTimeOffset throws an exception. What you wanted is this:

TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow).ToOffset(timeZone.BaseUtcOffset);

This will not throw the exception. I'm not sure why the constructor that accepts a TimeSpan even exists, since it only works if it matches the local or utc offset given in the DateTime object. But it is still possible with less headache.

2
votes

For those of us working with legacy systems, its not always possible to change the way the data is stored. If you are only interested in the specific time zone on the machine from which your code is running, you can use the below extension method. There is an implicit conversion between DateTime and DateTimeOffset which takes into account the "DateTime.Kind" property.

public static DateTimeOffset ToDateTimeOffset(this DateTime dt)
{
    return DateTime.SpecifyKind(dt, DateTimeKind.Local);
}