8

我刚刚开始正确考虑推出一个 web 应用程序,该应用程序需要在用户的一天开始时(比如早上 6 点)对他们做一些事情。也在他们生命的尽头。

我一直在读到人们说很多只是为了使用 .ToUniversalTime 以 UTC 存储时间,但是当我尝试这个时(我怀疑)它不起作用,它只是将时间移动了大约一个小时(我在英国,所以我认为这与从 GMT 到 UTC 的一些偏移有关,尽管这对我来说没有意义,因为目前应该关闭夏令时)。

我在数据库中有一个存储用户时区的字段,所以当我开始使用 ConvertTimeToUtc 和 fromUtc 时,它开始做我期望它做的事情。虽然我再次不确定我是否必须自己构建一些逻辑来进行夏令时转换,或者它应该为我做。

我主要想知道为什么每个人都在谈论.ToUniversalTime,因为它似乎对我没有帮助,而且我不明白它怎么可能知道将时间偏移到UTC,而第二种方式有道理。

有人可以解释每种方法如何有用吗?

4

3 回答 3

14

这两者其实有区别的。

在 .NET 3.5 及更低版本中,Datetime.ToUniversalTime实现为:

public DateTime ToUniversalTime() {
    return TimeZone.CurrentTimeZone.ToUniversalTime(this);
}

因为它使用了TimeZone该类,所以它遇到了 MSDN 文档中提到的相同问题:

该类TimeZone仅支持本地时区的单一夏令时调整规则。因此,TimeZone该类可以准确地报告夏令时信息或仅在最新调整规则生效期间在 UTC 和本地时间之间进行转换。相比之下,TimeZoneInfo该类支持多个调整规则,这使得处理历史时区数据成为可能。

在 .NET 4.0 及更高版本中,Datetime.ToUniversalTime实现为:

public DateTime ToUniversalTime() { 
    return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
} 

修复了不支持历史调整规则的问题,但是由于NoThrowOnInvalidTimeflag的原因,和刚才调用不一样TimeZoneInfo.ConvertimeToUtc

它调用的方法是一个带有标志的内部重载。公开版的方法用,而这个用的。ConvertTimeToUtcTimeZoneInfoOptionsTimeZoneInfoOptions.NoneTimeZoneInfoOptions.NoThrowOnInvalidTime

区别如下。时区设置为美国太平洋时间:

DateTime dt = new DateTime(2015, 3, 8, 2, 0, 0, DateTimeKind.Local);
DateTime utc = dt.ToUniversalTime();
Console.WriteLine(utc); // "3/8/2015 10:00:00 AM"

对比:

DateTime dt = new DateTime(2015, 3, 8, 2, 0, 0, DateTimeKind.Local);
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt);  // throws exception!
Console.WriteLine(utc);

由于在这个日期,在这个时区,时间从 1:59:59 跳到 3:00:00,提供 2:00:00 的本地时间是无效的。正确的做法是抛出异常(如第二种情况)。但是,由于DateTime.ToUniversalTime早期框架版本的现有合约不允许这样做,因此框架选择返回值而不是抛出。

它选择的值是根据使用标准时间偏移量计算的,就好像没有发生 DST 转换一样。

于 2015-07-05T19:24:06.533 回答
3

如果您在不同时区的机器上运行代码,您的计算是否仍然有效?这就是人们将所有 DateTimes 存储和处理为 UTC 的原因 - 它消除了任何歧义。您不需要存储用户的时区。任何地方的任何机器都可以从数据库中提取日期并轻松地将其转换为当地时间。

如果您将时间存储在其他时区,那么您必须将其拉出,计算与所需时区的偏移量,包括考虑夏令时和国际日期变更线的考虑。在您的情况下,您还存储了额外的不必要信息。

于 2009-11-10T00:24:39.057 回答
3

编辑:我错了。有关和的实现之间细微差别的解释,请参见 Matt Johnson 的回答DateTime.ToUniversalTimeTimeZoneInfo.ConvertTimeToUtc

对于其他在标题中提出特定问题的人:DateTime.ToUniversalTime 和 TimeZoneInfo.ConvertTimeToUtc 有什么区别

答案是:没有区别

使用 JustDecompile 检查DateTime.ToUniversalTime.NET 4.5 中的实现,我们看到它TimeZoneInfo.ConvertTimeToUtc直接使用:

    public DateTime ToUniversalTime()
    {
        return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
    }
于 2014-09-12T05:05:35.967 回答