Creating a DateTime in a specific Time Zone in c#
I'm trying to create a unit test to test the case for when the timezone changes on a machine because it has been incorrectly set and then corrected.
In the test I need to be able to create DateTime objects in a none local time zone to ensure that people running the test can do so successfully irrespective of where they are located.
From what I can see from the DateTime constructor I can set the TimeZone to be either the local timezone, the UTC timezone or not specified.
How do I create a DateTime with a specific timezone like PST?
Solution 1:
Jon's answer talks about TimeZone, but I'd suggest using TimeZoneInfo instead.
Personally I like keeping things in UTC where possible (at least for the past; storing UTC for the future has potential issues), so I'd suggest a structure like this:
public struct DateTimeWithZone
{
private readonly DateTime utcDateTime;
private readonly TimeZoneInfo timeZone;
public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
{
var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone);
this.timeZone = timeZone;
}
public DateTime UniversalTime { get { return utcDateTime; } }
public TimeZoneInfo TimeZone { get { return timeZone; } }
public DateTime LocalTime
{
get
{
return TimeZoneInfo.ConvertTime(utcDateTime, timeZone);
}
}
}
You may wish to change the "TimeZone" names to "TimeZoneInfo" to make things clearer - I prefer the briefer names myself.
Solution 2:
The DateTimeOffset structure was created for exactly this type of use.
See: http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx
Here's an example of creating a DateTimeOffset object with a specific time zone:
DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));
Solution 3:
The other answers here are useful but they don't cover how to access Pacific specifically - here you go:
public static DateTime GmtToPacific(DateTime dateTime)
{
return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}
Oddly enough, although "Pacific Standard Time" normally means something different from "Pacific Daylight Time," in this case it refers to Pacific time in general. In fact, if you use FindSystemTimeZoneById
to fetch it, one of the properties available is a bool telling you whether that timezone is currently in daylight savings or not.
You can see more generalized examples of this in a library I ended up throwing together to deal with DateTimes I need in different TimeZones based on where the user is asking from, etc:
https://github.com/b9chris/TimeZoneInfoLib.Net
This won't work outside of Windows (for example Mono on Linux) since the list of times comes from the Windows Registry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
Underneath that you'll find keys (folder icons in Registry Editor); the names of those keys are what you pass to FindSystemTimeZoneById
. On Linux you have to use a separate Linux-standard set of timezone definitions, which I've not adequately explored.
Solution 4:
I altered Jon Skeet answer a bit for the web with extension method. It also works on azure like a charm.
public static class DateTimeWithZone
{
private static readonly TimeZoneInfo timeZone;
static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}
public static DateTime LocalTime(this DateTime t)
{
return TimeZoneInfo.ConvertTime(t, timeZone);
}
}