代码之家  ›  专栏  ›  技术社区  ›  Jack Hughes

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

  •  123
  • Jack Hughes  · 技术社区  · 16 年前

    我正在尝试创建一个单元测试来测试机器上时区因设置不正确而发生更改的情况,然后再进行更正。

    在测试中,我需要能够在非本地时区中创建日期时间对象,以确保运行测试的人员可以成功地执行此操作,而不管他们位于何处。

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

    如何创建具有特定时区(如pst)的日期时间?

    6 回复  |  直到 6 年前
        1
  •  174
  •   Community CDub    7 年前

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

    你可能想把“时区”改成“时区信息”,让事情更清楚些——我自己更喜欢简短的名字。

        2
  •  42
  •   CleverPatrick    15 年前

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

        3
  •  29
  •   Hooligancat    6 年前

    这里的其他答案是有用的,但它们不包括如何特别访问太平洋-这里是:

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

    奇怪的是,尽管“太平洋标准时间”通常意味着不同于“太平洋昼时”,在本例中,它一般指太平洋时间。事实上,如果你使用 FindSystemTimeZoneById 要获取它,可用的属性之一是一个bool,告诉您时区当前是否处于夏令时状态。

    您可以在我最后拼凑起来的一个库中看到更广泛的例子,根据用户的请求,处理我在不同时区需要的日期时间,等等:

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

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

    在下面,您可以找到键(注册表编辑器中的文件夹图标);这些键的名称就是您要传递到的。 查找系统时区ID . 在Linux上,您必须使用一组单独的Linux标准时区定义,我还没有充分探讨过。

        4
  •  6
  •   Community CDub    7 年前

    我改变了 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);   
    }
    }
    
        5
  •  2
  •   Jon Limjap    16 年前

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

    不确定是否已经有一个clr提供的数据类型具有该类型,但至少时区组件已经可用。

        6
  •  2
  •   Gabe Halsmer    11 年前

    我喜欢乔恩·斯基特的回答,但想补充一点。我不确定Jon是否希望在本地时区始终传递ctor。但我想把它用于其他地方的情况。

    我正在从数据库中读取值,我知道数据库在哪个时区。所以在ctr中,我将传递数据库的时区。但是我想要当地时间的值。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);
    }