在c#中的特定时区创建日期时间

时间:2008-10-29 11:48:06

标签: c# .net datetime .net-3.5

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

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

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

如何使用PST等特定时区创建DateTime?

7 个答案:

答案 0 :(得分:180)

Jon's answer谈到TimeZone,但我建议改为使用TimeZoneInfo

就个人而言,我喜欢在可能的情况下保留UTC(至少在过去; storing UTC for the future has potential issues),所以我建议这样的结构:

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

答案 1 :(得分:43)

为这种类型的使用创建了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));

答案 2 :(得分:31)

此处的其他答案很有用,但它们并未涵盖如何专门访问太平洋 - 请转到此处:

public static DateTime GmtToPacific(DateTime dateTime)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
        TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}

奇怪的是,虽然“太平洋标准时间”通常意味着与“太平洋夏令时”不同,但在这种情况下,它指的是太平洋时间。实际上,如果你使用FindSystemTimeZoneById来获取它,那么可用的一个属性是bool,告诉你该时区目前是否在夏令时中。

你可以在一个库中看到更多关于这个的一般化例子我最终会根据用户提出的问题来处理不同时区的DateTimes,等等:

https://github.com/b9chris/TimeZoneInfoLib.Net

这不适用于Windows之外(例如Linux上的Mono),因为时间列表来自Windows注册表: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

在下面你会找到密钥(注册表编辑器中的文件夹图标);这些键的名称是您传递给FindSystemTimeZoneById的名称。在Linux上,你必须使用一组单独的Linux标准时区定义,我没有充分研究过。

答案 3 :(得分:6)

我使用扩展方法为网络改变了一点Jon Skeet answer。它也适用于天蓝色的魅力。

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

答案 4 :(得分:2)

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

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

答案 5 :(得分:2)

我喜欢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);
}

答案 6 :(得分:0)

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

TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(TimeZones.Paris.Id));