简体   繁体   中英

get DateTimeOffset from DateTime (utc) and TimeZoneInfo

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..

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)));
}

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);

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.

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM