50

I have a UTC DateTime value coming from a database record. I also have a user-specified time zone (an instance of TimeZoneInfo). How do I convert that UTC DateTime to the user's local time zone? Also, how do I determine if the user-specified time zone is currently observing DST? I'm using .NET 3.5.

Thanks, Mark

Mark Richman
  • 28,948
  • 25
  • 99
  • 159

6 Answers6

62

The best way to do this is simply to use TimeZoneInfo.ConvertTimeFromUtc.

// you said you had these already
DateTime utc = new DateTime(2014, 6, 4, 12, 34, 0);
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");

// it's a simple one-liner
DateTime pacific = TimeZoneInfo.ConvertTimeFromUtc(utc, tzi);

The only catch is that the incoming DateTime value may not have the DateTimeKind.Local kind. It must either be Utc, or Unspecified.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Ugh, if they had only made the Convert function a member of the tzi instance instead of a static I wouldn't have to come to stackoverflow to figure this out. – MarkPflug Oct 21 '21 at 19:18
26

You can use a dedicated function within TimeZoneInfo if you want to convert a DateTimeOffset into another DateTimeOffset:

DateTimeOffset newTime = TimeZoneInfo.ConvertTime(
    DateTimeOffset.UtcNow, 
    TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
);
Boris Schegolev
  • 3,601
  • 5
  • 21
  • 34
Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
22

Have a look at the DateTimeOffset structure:

// user-specified time zone
TimeZoneInfo southPole =
    TimeZoneInfo.FindSystemTimeZoneById("Antarctica/South Pole Standard Time");

// an UTC DateTime
DateTime utcTime = new DateTime(2007, 07, 12, 06, 32, 00, DateTimeKind.Utc);

// DateTime with offset
DateTimeOffset dateAndOffset =
    new DateTimeOffset(utcTime, southPole.GetUtcOffset(utcTime));

Console.WriteLine(dateAndOffset);

For DST see the TimeZoneInfo.IsDaylightSavingTime method.

bool isDst = southpole.IsDaylightSavingTime(DateTime.UtcNow);
dtb
  • 213,145
  • 36
  • 401
  • 431
  • I have to go one extra step to get my local time: var offset = tzi.GetUtcOffset(utcTime); var siteLocalTime = utcTime.Add(offset); return siteLocalTime.ToString("MM/dd/yyyy HH:mm"); – Mark Richman Mar 30 '10 at 23:08
  • 10
    This code doesn't compile. That time zone Id doesn't exist and if you replace it with a valid one then you get an error about `The UTC Offset for Utc DateTime instances must be 0`. – The Muffin Man Apr 14 '14 at 01:12
  • to avoid error in dateAndOffset choose DateTime cstTime = utcTime.AddTicks(southPole.BaseUtcOffset.Ticks); – Saneesh kunjunni Aug 29 '17 at 05:53
13

The Antartica answer only works for the timezones matching UTC. I'm quite traumatized with this DateTimeOffset function and after hours of trial and error, I've managed to produce a practical conversion extension function that works with all timezones.

static public class DateTimeFunctions
{
    static public DateTimeOffset ConvertUtcTimeToTimeZone(this DateTime dateTime, string toTimeZoneDesc)
    {
        if (dateTime.Kind != DateTimeKind.Utc) throw new Exception("dateTime needs to have Kind property set to Utc");
        var toUtcOffset = TimeZoneInfo.FindSystemTimeZoneById(toTimeZoneDesc).GetUtcOffset(dateTime);
        var convertedTime = DateTime.SpecifyKind(dateTime.Add(toUtcOffset), DateTimeKind.Unspecified);
        return new DateTimeOffset(convertedTime, toUtcOffset);
    }
}

Example:

var currentTimeInPacificTime = DateTime.UtcNow.ConvertUtcTimeToTimeZone("Pacific Standard Time");
Anuj Balan
  • 7,629
  • 23
  • 58
  • 92
Sean
  • 2,531
  • 2
  • 17
  • 17
2

Here's another gotcha: If you're running your code on a Linux server, you need to use the Linux system for timezone names. For example, "Central Standard Time" would be "America/Chicago". The tz list is here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

Here's an example with the isWindows switch:

public static class DateTimeHelper
{
    public static string ConvertUtcToCst(this string dateTimeString)
    {
        if (string.IsNullOrWhiteSpace(dateTimeString))
        {
            return string.Empty;
        }

        if (DateTime.TryParse(dateTimeString, out DateTime outputDateTime))
        {
            try
            {
                var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                TimeZoneInfo cstZone = null;
                if (isWindows)
                {
                    cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
                }
                else
                {
                    cstZone = TimeZoneInfo.FindSystemTimeZoneById("America/Chicago");
                }

                var cstDateTime = TimeZoneInfo.ConvertTimeFromUtc(outputDateTime, cstZone);
                return cstDateTime.ToString();
            }
            catch (TimeZoneNotFoundException)
            {
                return "The registry does not define the Central Standard Time zone.";
            }
            catch (InvalidTimeZoneException)
            {
                return "Registry data on the Central Standard Time zone has been corrupted.";
            }
            catch (Exception ex)
            {
                return $"Error :: {ex.Message} :: {ex.ToString()}";
            }
        }

        return string.Empty;
    }
}
Robert Corvus
  • 2,054
  • 23
  • 30
1
       //  TO get Currrent Time in current Time Zone of your System

        var dt = DateTime.Now;

        Console.WriteLine(dt);

        // Display Time Zone of your System

        Console.WriteLine(TimeZoneInfo.Local);

        // Convert Current Date Time to UTC Date Time

        var utc = TimeZoneInfo.ConvertTimeToUtc(dt, TimeZoneInfo.Local);

        Console.WriteLine(utc);

        // Convert UTC Time to Current Time Zone

        DateTime pacific = TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.Local);

        Console.WriteLine(pacific);

        Console.ReadLine();
Srinivas
  • 22,589
  • 1
  • 14
  • 4