代码之家  ›  专栏  ›  技术社区  ›  Thomas

在C中使用夏令时处理时区#

  •  2
  • Thomas  · 技术社区  · 6 年前

    我们有一个与航空相关的应用程序,特别是航班。

    时间必须存储在本地,所以我选择使用UTC时间+偏移量,但现在我意识到这是一个错误的选择:

    通过将时区存储为偏移量,我无法跟踪原始时区,这对处理夏令时有影响。

    例如,我可以在阿尔卑斯山存储一个时间,UT为UTC时间和a-6偏移量,在凤凰城存储一个时间,AZ为UTC时间和a-6偏移量。

    但当夏时制到来时,阿尔卑斯山的时间会改变,而凤凰城的时间不会改变。

    因此,我需要存储适当的时区,并且我已经看到也有不同语法的不同列表,所以我假设有不同的标准。

    在C#中,将本地时间与本地时区存储在一起以使其适用于夏令时更改的最佳选项是什么?

    2 回复  |  直到 6 年前
        1
  •  5
  •   Matt Johnson-Pint    6 年前

    从问题评论中的讨论中,我了解到您正在处理航班时刻表,即未来航班计划起飞的时间。在这种情况下,当地时间比UTC时间更重要。

    由于您有当地出发时间和地点(例如盐湖城下午5:00),因此您应该在计划出发时间数据库中存储两个值:

    • 17:00 -出发的相关当地时间
    • SLC -时间相关的位置

    如果这是 具体的 如果发生此航班,则您还应存储日期:

    • 2018-06-01T17:00 -The 具体的 当地相关出发时间
    • SLC公司 -与当地时间相关的位置

    这些是与您的业务用例上下文相关的细节。通过将其转换为UTC,不要忽视它们 .

    也就是说,您可以考虑将它们存储为 DateTimeOffset ( 2018-06-01T17:00-06:00 ),这使得转换为UTC对于给定实例来说非常简单。然而,这种方法存在两个问题:

    • 它无法处理重复,因为偏移可能会更改。
    • 即使对于单个实例,偏移 可以 更改-如果控制时区的政府决定在该事件生效之前更改其标准偏移或夏令时规则。如果你真的 日期时间偏移量 方法或基于UTC的方法,您必须准备好面对此类更改重新计算未来事件。(有关这方面的更多信息,请参阅我的博客文章: On the Timing of Time Zone Changes Time Zone Chaos Inevitable in Egypt . 还有无数其他例子。)

    关于位置-由于您使用的数据在上下文中适用于航空业,我建议使用IATA机场代码,如 SLC公司 我在上面展示的。在其他上下文中,可以存储IANA时区标识符,如 America/Denver ,或Windows时区标识符,如 Mountain Standard Time .

    你可能会发现 my "Airport Time Zones" gist (code and output table) 适用于使用IATA机场代码。您必须决定数据将如何流经您的系统。如果您在Windows上运行,并且希望使用 TimeZoneInfo 类将时间转换为不同的时区,然后使用此处显示的Windows时区ID。如果要使用IANA时区ID,请考虑使用 Noda Time ,或者您可以使用 TimeZoneConverter 图书馆这里有几种不同的选择,所以请仔细研究它们并选择对您有意义的。

    野田时间会是个不错的选择,IMHO。您不仅可以获得出色的时区支持,还可以使用以下类型 LocalTime LocalDateTime 这与所描述的场景非常吻合。

        2
  •  1
  •   Zohar Peled    6 年前

    正如我在评论中所写, 请勿 存储本地日期。相反,将日期时间值存储为UTC,并在需要显示时转换为本地日期时间。
    您可以使用 ConvertTimeFromUtc 的方法 TimeZoneInfo 这方面的课程。

    这意味着您还必须保留一个位置列表以及它们关联的任何时区信息,例如,
    Jerusalem 将与关联 Israel Standard Time ,
    Rome 具有 W. Europe Standard Time ,
    Hawaii 具有 Hawaiian Standard Time
    等等(我敢打赌,你可以在网上的某个地方找到这样的列表。)
    请注意 ConvertTimeFromUtc 方法也可以为您处理夏令时问题。

    然后,您可以通过以下操作按位置获取当地时间:

    DateTime GetLocalDateByCityName(DateTime utc, string cityName)
    {
        var timeZoneInfoId = GetTimeZoneInfoIdByCityName(string cityName);
        return TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.FindSystemTimeZoneById(timeZoneInfoId);
    }
    

    当然,在 GetTimeZoneInfoIdByCityName 您可以获得特定城市的时区信息。