当服务器设置为UTC时,创建夏令时感知的DateTime

时间:2014-01-06 08:10:05

标签: c# datetime azure utc dst

我的应用程序托管在Windows Azure上,其中所有服务器都设置为UTC。

我需要知道任何给定的DateTime何时受夏令时影响。为简单起见,我们可以假设我的用户都在英国(因此使用格林威治标准时间)。

我用来转换DateTime个对象的代码是

public static DateTime UtcToUserTimeZone(DateTime dateTime)
{
    dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);

    var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Greenwich Standard Time");

    var userDateTime = TimeZoneInfo.ConvertTime(dateTime, timeZone);

    return DateTime.SpecifyKind(userDateTime, DateTimeKind.Local);
}

然而,以下测试在最后一行失败;转换后的DateTime不知道它应该是夏令时。

[Test]
public void UtcToUserTimeZoneShouldWork()
{
    var utcDateTime = new DateTime(2014, 6, 1, 12, 0, 0, DateTimeKind.Utc);
    Assert.IsFalse(utcDateTime.IsDaylightSavingTime());

    var dateTime = Utils.UtcToUserTimeZone(utcDateTime);
    Assert.IsTrue(dateTime.IsDaylightSavingTime());
}

请注意,仅当我的Windows时区设置为(UTC)协调世界时时,此操作才会失败。当它设置为(UTC)都柏林,爱丁堡,里斯本,伦敦(或观察夏令时的任何其他北半球时区)时,测试通过。如果在Windows中更改此设置,则需要重新启动Visual Studio才能使更改完全生效。

我错过了什么?

2 个答案:

答案 0 :(得分:5)

您的最后一行指定该值位于其运行的系统的本地时区 - 但实际上并非......它是使用不同的时区转换的。

基本上DateTimesomewhat broken,在我看来 - 这使得很难正确使用。没有办法说“此DateTime值在时区x” - 您可以执行转换以查找特定的本地时间,但不记得时区。

例如,来自DateTime.IsDaylightSavingTime(强调我的)的文档:

  

此方法确定当前DateTime值是否属于本地时区的夏令时时间范围,该范围由TimeZoneInfo.Local属性返回。

显然我有偏见,但我建议使用我的Noda Time项目 - 很可能使用ZonedDateTime。您可以致电GetZoneInterval获取ZonedDateTime的{​​{3}},然后使用ZoneInterval检查当前偏移量是否包含夏令时组件:

bool daylight = zonedDateTime.GetZoneInterval().Savings != Offset.Zero;

这有点啰嗦...我添加了ZoneInterval.Savings以考虑向IsDaylightSavingTime()添加ZonedDateTime方法......

答案 1 :(得分:3)

  • 您遗漏的主要内容是“格林威治标准时间”伦敦的TimeZoneInfo ID。那个人实际上属于“(UTC)蒙罗维亚,雷克雅未克”。

    你想要“GMT标准时间”,它映射到“(UTC)Dublin,Edinburgh,Lisbon,London”

    是的,Windows时区很奇怪。 (至少你不住在法国,这被奇怪地标记为“浪漫标准时间”!)

  • 此外,您正在执行此部分:

    return DateTime.SpecifyKind(userDateTime, DateTimeKind.Local);
    

    这将使各种其他代码认为它来自本地机器的时区。保留“未指定”类型。 (或者甚至更好,使用DateTimeOffset代替DateTime

  • 然后,您还需要在.IsDaylightSavingsTime对象上使用TimeZoneInfo方法,而不是.DateTime对象上的方法。 (两个不同的方法,具有相同的名称,在不同的对象上,具有不同的行为。哎哟!)

但我完全同意这太复杂且容易出错。只需使用Noda Time即可。你会很高兴你做到了!