197

我正在尝试创建一个单元测试来测试机器上时区何时更改的情况,因为它已被错误地设置然后更正。

在测试中,我需要能够在非本地时区创建 DateTime 对象,以确保运行测试的人无论身在何处都可以成功地做到这一点。

从我从 DateTime 构造函数中可以看到,我可以将 TimeZone 设置为本地时区、UTC 时区或未指定。

如何创建具有特定时区(如 PST)的 DateTime?

4

9 回答 9

250

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”以使事情更清晰 - 我自己更喜欢更简短的名称。

于 2008-10-29T12:00:15.860 回答
65

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

于 2009-08-15T02:32:07.340 回答
51

这里的其他答案很有用,但它们没有具体介绍如何访问太平洋 - 你去吧:

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 标准时区定义,我还没有充分探索。

于 2012-01-27T00:24:49.180 回答
7

我使用扩展方法为网络更改了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);   
}
}
于 2014-04-03T06:47:01.260 回答
3

我喜欢 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);
}
于 2013-12-10T20:13:18.143 回答
2

您必须为此创建一个自定义对象。您的自定义对象将包含两个值:

  • 日期时间值
  • 对象

不确定是否已经存在 CLR 提供的数据类型,但至少 TimeZone 组件已经可用。

于 2008-10-29T11:51:21.590 回答
1

使用TimeZones类可以轻松创建时区特定日期。

TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(TimeZones.Paris.Id));
于 2019-10-01T16:39:38.463 回答
0

尝试TimeZoneInfo.ConvertTime(dateTime, sourceTimeZone, destinationTimeZone)

于 2021-09-16T08:46:36.500 回答
0

对于具有特定时区(既不是本地的,也不是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);
于 2021-11-10T12:46:38.907 回答