首页 文章

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

提问于
浏览
121

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

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

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

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

6 回答

  • 172

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

    就个人而言,我喜欢在可能的情况下保留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”以使事情更清晰 - 我更喜欢自己的名字 .

  • 6

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

  • 29

    这里的其他答案很有用,但它们没有涵盖如何专门访问太平洋 - 在这里你去:

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

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

    您可以在库中看到更多关于此的一般化示例我最终会根据用户询问的位置等在不同的TimeZones中处理我需要的DateTimes:

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

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

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

  • 41

    我用扩展方法为web改变了一点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);   
    }
    }
    
  • 2

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

    • 一个DateTime值

    • 一个TimeZone对象

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

  • 2

    我喜欢Jon Skeet的回答,但想补充一点 . 我不确定Jon是否期望ctor始终在本地时区传递 . 但是我想把它用于那些本地以外的东西 .

    我正在读取数据库中的值,我知道数据库所处的时区 . 所以在ctor中,我将传入数据库的时区 . 但后来我想在当地时间 Value . 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);
    }
    

相关问题