24

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

katit
  • 17,375
  • 35
  • 128
  • 256
  • Related question: http://stackoverflow.com/q/2532729/1583 – Oded Jun 08 '11 at 19:43
  • Use `DateTime.Now`, not `DateTime.UtcNow`. – Oded Jun 08 '11 at 19:44
  • This is just illustration of the problem. My data source has all the dates marked as Utc. I need to convert them to different TimeZones – katit Jun 08 '11 at 19:46
  • Don't use `TimeZoneInfo` - just create a new `TimeSpan` with all fields set to 0. – Oded Jun 08 '11 at 19:56
  • @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 UI – katit Jun 08 '11 at 20:08

4 Answers4

23

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)));
}
Nuri YILMAZ
  • 4,291
  • 5
  • 37
  • 43
Dave Ferguson
  • 1,456
  • 13
  • 17
  • I wish it was that simple. I'm working on location-based app. So, I need to display times in various zones. Yes, I store them in UTC but I'm working on function which converts UTC time into locale time based on other (location) parameter. It's not your simpe DateTime.ConvertToLocal.. – katit Jun 08 '11 at 19:40
  • It is not what I want. Let's say your PC on Central time. I want to display UTC date in Pacific Time. – katit Jun 08 '11 at 19:45
  • @katit I just added an option where you can take any timezoneinfo object and convert a UTC date to a datetime local to that timezone. – Dave Ferguson Jun 08 '11 at 19:47
  • My goal is to get DateTimeOffset object with date and zone insidie of it.. Then when I will display it - I will deal with it separately – katit Jun 08 '11 at 20:09
7

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);
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • That doesn't work - I get exception: The UTC Offset for Utc DateTime instances must be 0.\r\nParameter name: offset Maybe because myDateTime has kind "Utc" ? – katit Jun 08 '11 at 19:37
  • @katit - That sounds reasonable. If your `DateTime` variable is of type `Local`, then a `TimeSpan` of `0` is indeed correct. – Oded Jun 08 '11 at 19:40
4

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.

Garr Godfrey
  • 8,257
  • 2
  • 25
  • 23
2

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);
}
rdans
  • 2,179
  • 22
  • 32
  • 1
    Thanks for this, I was able to replace `TimeZoneInfo.Local.GetUtcOffset(time).Hours` with `((DateTimeOffset)DateTime.SpecifyKind(time, DateTimeKind.Local)).Offset.Hours` for my Windows build, and I no longer get an exception. – BenV May 06 '16 at 22:21