【问题标题】:.NET: Accounting for daylight savings.NET:考虑夏令时
【发布时间】:2011-08-14 06:04:30
【问题描述】:

我有一种方法可以根据用户输入创建 UTC DateTime,使用他们地理位置的 GMT 偏移量:

public static DateTime LocalToUtc
    (int year, int month, int day, int hour, decimal gmtOffset) {

    // argument validation here

    var dateTime = new DateTime(year, month, day).AddHours(hour);
    var dateTimeOffset = 
        new DateTimeOffset(dateTime, TimeSpan.FromHours(gmtOffset));

    return dateTimeOffset.UtcDateTime;

} 

问题是,如果用户所在时区是夏令时,此功能会关闭一个小时。

因此,虽然我个人的 GMT 偏移量是 -8,但由于夏令时,当前时区偏移量是 -7。

如何更改上述函数以考虑夏令时?难道我不需要从 GMT 偏移量创建一些时区对象并获取它的时区偏移量吗?

【问题讨论】:

    标签: c# .net datetime localization


    【解决方案1】:

    在不知道实际时区的情况下无法做到这一点:多个时区具有相同的基本 UTC 偏移量,但夏令时的规则不同。例如,W。欧洲标准时间W。中非标准时间 都有 +01:00 的偏移量,但前者支持 DST 而后者不支持。所以偏移量不足以决定DST是否适用......

    您的方法应该采用TimeZoneInfo 参数而不是gmtOffset。这样你就可以使用TimeZoneInfo.ConvertTime方法来转换日期,它会自动考虑夏令时。

    【讨论】:

    • 好的,假设我有数据告诉我他们所在的时区。如何创建 TimeZoneInfo 对象?换句话说,我们将参数更改为 TimeZoneInfo。好的。然后我们需要一个 TimeZoneInfo 对象来发送给函数。它是如何构建的?
    • 您可以使用TimeZoneInfo.FindSystemTimeZoneById 方法。或者您可以使用TimeZoneInfo.GetSystemTimeZones 方法获取所有时区的列表,并让用户从该列表中进行选择。
    • 或者你可以调用 TimeZoneInfo.CreateCustomTimeZone 来实例化你想要的任何时区。
    【解决方案2】:

    DateTime 已经有方法可以做到这一点,称为 ToLocalTime()ToUniversalTime()。使用它有什么问题?

    编辑:

    根据作者希望从当前计算机时区以外的时区转换为 utc 的评论,我建议您参考 John Skeets 的回答 Here

    来自MSDN documentation

    string displayName = "(GMT+06:00) Antarctica/Mawson Time";
    string standardName = "Mawson Time"; 
    TimeSpan offset = new TimeSpan(06, 00, 00);
    TimeZoneInfo mawson = TimeZoneInfo.CreateCustomTimeZone(standardName, 
        offset, displayName, standardName);
    Console.WriteLine("The current time is {0} {1}", 
                      TimeZoneInfo.ConvertTime(DateTime.Now, 
                           TimeZoneInfo.Local, mawson), mawson.StandardName);      
    

    【讨论】:

    • DateTime 在不同时区的差异值时有问题。当根本没有设置 UTC 类型时,尤其令人讨厌。
    • @GregC - 不,它不是错误的。您不能总是确定 DateTime 具有正确的本地时间信息集。这就是您转换为 UTC 进行比较的原因。
    • @Mystere Man,GregC 是对的,DateTime 结构不适合处理不同的时区。这正是引入 DateTimeOffset 结构的原因...
    • @Mystere Man:尝试使用 DateTime.Now 创建一个新的 DateTime 对象,并使用 DateTime.UtcNow 创建另一个。有所不同。观察错误(除非你在 GB)。
    • 当 DateTime 中不包含 GMT 偏移信息时,如何使用 new DateTime(year, month, day).AddHours(hour).ToUniversalTime()?它如何知道使用哪个 GMT?
    【解决方案3】:

    如果您不想使用内置的 UTC 方法,则应使用 TimeZone.GetUtcOffset 方法。

    http://msdn.microsoft.com/en-us/library/system.timezone.getutcoffset.aspx

    它将为您提供与 UTC 的偏移量。您还可以使用内置方法从当地时间获取 UTC 时间。

    http://msdn.microsoft.com/en-us/library/system.datetime.touniversaltime(v=VS.100).aspx

    【讨论】:

    • 如何获取 TimeZone 对象以调用 GetUtcOffset?我只知道用户的 GMT 偏移量。
    【解决方案4】:

    因为听起来您是在向用户询问可能不一定在机器本地时区的时间偏移,所以本地机器时间不起作用。但是使用 TimeZoneInfo 类,您应该能够构造一个说明偏移量和 DST 状态的实例,并从那里使用内置方法。

    编辑:至少在我的机器上,TimeZoneInfo.GetSystemTimeZones() 似乎返回了所有有效的时区。这可以很容易地映射到一个下拉菜单以允许用户选择。

    【讨论】:

    • GMT 偏移量是根据地理数据集计算得出的。他们必须在注册时选择他们的 lat/lng。然后在派生 GMT 偏移量的数据库表中查找该 lat/lng。
    • 他们是专门输入纬度/经度来获取时区,还是也用于其他目的?如果没有,您可以使用TimeZoneInfo.GetSystemTimeZones() 并为用户提供下拉选择。或者:这个数据集是否只提供偏移量或 DST 信息?如果它有 DST 信息,您可以动态创建 TimeZoneInfo 的自定义实例。
    猜你喜欢
    • 2013-09-22
    • 1970-01-01
    • 2018-01-01
    • 2012-07-03
    • 2020-09-12
    • 2020-03-01
    • 2014-06-01
    • 2018-02-04
    • 2017-09-15
    相关资源
    最近更新 更多