我正在尝试创建一个单元测试来测试机器上时区何时更改的情况,因为它已被错误地设置然后更正。
在测试中,我需要能够在非本地时区创建 DateTime 对象,以确保运行测试的人无论身在何处都可以成功地做到这一点。
从我从 DateTime 构造函数中可以看到,我可以将 TimeZone 设置为本地时区、UTC 时区或未指定。
如何创建具有特定时区(如 PST)的 DateTime?
Jon 的回答谈到了TimeZone,但我建议改用TimeZoneInfo。
就我个人而言,我喜欢尽可能保持 UTC 格式(至少在过去;为未来存储 UTC存在潜在问题),所以我建议采用这样的结构:
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);
}
}
}
您可能希望将“TimeZone”名称更改为“TimeZoneInfo”以使事情更清晰 - 我自己更喜欢更简短的名称。
DateTimeOffset 结构正是为这种类型的使用而创建的。
请参阅:http: //msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx
下面是创建具有特定时区的 DateTimeOffset 对象的示例:
DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));
这里的其他答案很有用,但它们没有具体介绍如何访问太平洋 - 你去吧:
public static DateTime GmtToPacific(DateTime dateTime)
{
return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}
奇怪的是,虽然“太平洋标准时间”通常意味着与“太平洋夏令时间”不同的东西,但在这种情况下,它通常指的是太平洋时间。事实上,如果您使用FindSystemTimeZoneById
它来获取它,其中一个可用属性是一个布尔值,告诉您该时区当前是否处于夏令时。
您可以在一个库中看到更通用的示例,我最终根据用户要求的位置等来处理我在不同时区中需要的 DateTimes:
https://github.com/b9chris/TimeZoneInfoLib.Net
这在 Windows 之外不起作用(例如 Linux 上的 Mono),因为时间列表来自 Windows 注册表:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
在其下方,您会找到键(注册表编辑器中的文件夹图标);这些键的名称是您传递给FindSystemTimeZoneById
. 在 Linux 上,您必须使用一组单独的 Linux 标准时区定义,我还没有充分探索。
我使用扩展方法为网络更改了Jon Skeet 的答案。它也像魅力一样适用于天蓝色。
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);
}
}
我喜欢 Jon Skeet 的回答,但想补充一件事。我不确定 Jon 是否期望 ctor 总是在本地时区传递。但我想将它用于其他地方的情况。
我正在从数据库中读取值,并且我知道该数据库所在的时区。所以在 ctor 中,我将传入数据库的时区。但是我想要当地时间的价值。Jon 的 LocalTime 不会返回转换为本地时区日期的原始日期。它返回转换为原始时区的日期(无论您传递给 ctor)。
我认为这些属性名称清楚...
public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}
使用TimeZones类可以轻松创建时区特定日期。
TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(TimeZones.Paris.Id));
尝试TimeZoneInfo.ConvertTime(dateTime, sourceTimeZone, destinationTimeZone)
对于具有特定时区(既不是本地的,也不是UTC)的偏移量的日期/时间,您可以使用 DateTimeOffset 类:
var time = TimeSpan.Parse("9:00");
var est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var nationalDateTime = new DateTimeOffset(DateTime.Today.Ticks + time.Ticks, est.BaseUtcOffset);