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

Jac*_*hes 139 .net c# timezone datetime .net-3.5

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

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

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

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

Jon*_*eet 194

Jon的回答谈到了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); 
        }
    }        
}
Run Code Online (Sandbox Code Playgroud)

您可能希望将"TimeZone"名称更改为"TimeZoneInfo"以使事情更清晰 - 我更喜欢自己的简短名称.

  • @ChrisMoschini:我会继续建议使用行业标准的,明确的zoneinfo ID而不是模糊的缩写.这不是图书馆首选的问题 - 图书馆的作者真的不是问题.如果有人希望使用另一个带有*良好*标识符选择的库,那很好.时区的标识符的选择是重要的,我认为读者知道缩写*是*不明确是非常重要的,正如我在IST示例中所示. (6认同)
  • 我不知道有任何等效的SQL Server构造,我担心.我建议将时区名称作为一列,将UTC值作为另一列.单独获取它们然后您可以相当容易地创建实例. (5认同)
  • 不确定使用DateTime和TimeZoneInfo的构造函数的预期用法,但鉴于你正在调用dateTime.ToUniversalTime()方法,我怀疑你猜测它可能在当地时间.在这种情况下,我认为你应该真正使用传入的TimeZoneInfo将其转换为UTC,因为他们告诉你它应该在那个时区. (2认同)
  • @ChrisMoschini:那时,您只是在发明自己的ID方案-世界上其他任何人都不会使用的方案。谢谢,我坚持使用行业标准的zoneinfo。(例如,很难看到“欧洲/伦敦”是什么意思。) (2认同)
  • @ChrisMoschini:然后是另一个示例:CST。是UTC-5还是UTC-6?IST-您的数据库中是以色列,印度还是爱尔兰?(即使您现在知道偏移量,观察相同缩写的不同国家/地区可能在不同时间也会发生变化。因此,对于哪个实际时区,它仍然意味着含糊。时区!=偏移量。)回到您的情况:您主张使用缩写词可以最好地解决您的问题。使用行业标准时区ID会变得更糟吗? (2认同)

Cle*_*man 48

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

  • 课.DST是特定时区的规则.DateTimeOffset不会与任何时区无关.不要将UTC偏移值(例如-5)与时区混淆.这不是一个时区,它是一个偏移.许多时区通常共享相同的偏移量,因此这是一种引用时区的模糊方式.由于DateTimeOffset与偏移量而不是时区相关联,因此无法应用DST规则.所以凌晨3点将是每年的每一天凌晨3点,毫无例外地在DateTimeOffset结构中(例如在它的Hours和TimeOfDay属性中). (8认同)
  • 因此,DateTimeOffset的真正问题在于它没有包含足够的信息.它包括一个偏移,而不是一个时区.多个时区的偏移量不明确. (3认同)
  • 谢谢,这是实现这一目标的好方法。在获得正确时区内的 DateTimeOffset 对象后,您可以使用 .UtcDateTime 属性来获取您创建的对象的 UTC 时间。如果您将日期存储为 UTC,那么将它们转换为每个用户的本地时间并不是什么大问题:) (2认同)
  • 我认为这不能正确处理夏令时,因为某些时区尊重它而其他时区则不尊重它。此外,“当天”夏令时开始/结束,当天的部分时间将关闭。 (2认同)

Chr*_*ini 36

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

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

奇怪的是,虽然"太平洋标准时间"通常意味着与"太平洋夏令时"不同,但在这种情况下,它指的是太平洋时间.实际上,如果您使用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标准时区定义,我没有充分研究过.

  • 另外还有 ConvertTimeBySystemTimeZoneId() 例如: TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.UtcNow, "Central Standard Time") (2认同)

Jer*_*vak 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);   
}
}
Run Code Online (Sandbox Code Playgroud)