Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 解决数据库中存储的日期值的不明确时间_C#_.net_Datetime_Timezone_Nodatime - Fatal编程技术网

C# 解决数据库中存储的日期值的不明确时间

C# 解决数据库中存储的日期值的不明确时间,c#,.net,datetime,timezone,nodatime,C#,.net,Datetime,Timezone,Nodatime,在英国,时钟在2014年10月26日凌晨02:00倒回1小时。在这种情况下,英国的每个人都在当天观察了两次01:00到01:59之间的时间 假设我有一个.NET软件应用程序,其中日期和时间在特定时区非常重要。在这种情况下,当我在数据存储系统中看到10月26日01:00时,我应该推断什么?我应该存储时区,如BST和GMT,还是应该存储偏移值 我通常对在这种情况下该怎么办感到困惑(希望我不是唯一一个困惑的人:D)。原因是时区缩写可以有多种含义,如BST: 对于这些情况,特别是在.NET应用程

在英国,时钟在2014年10月26日凌晨02:00倒回1小时。在这种情况下,英国的每个人都在当天观察了两次01:00到01:59之间的时间

假设我有一个.NET软件应用程序,其中日期和时间在特定时区非常重要。在这种情况下,当我在数据存储系统中看到10月26日01:00时,我应该推断什么?我应该存储时区,如BST和GMT,还是应该存储偏移值

我通常对在这种情况下该怎么办感到困惑(希望我不是唯一一个困惑的人:D)。原因是时区缩写可以有多种含义,如BST:

对于这些情况,特别是在.NET应用程序中,什么是最佳实践(BCL DateTime值类型和NodaTime解决方案都值得赞赏)

编辑1 有一些关于坚持UTC的建议。然而,想象一下,我需要知道这个应用程序中的时区。机票申请就是一个例子。你会从一个时区起飞,然后降落到另一个时区。即使我们可以将日期和时间转换为UTC,并将时区存储在附近,但我仍然无法找到解决时间不明确问题的正确方法,这正是问题的关键所在。下面的操作非常有效(BCL值类型,而不是节点时间):

下面这一条失败得很惨:

    static void ConvertToAndFromUtcWrongly()
    {
        const string ukTimeZoneId = "GMT Standard Time";
        TimeZoneInfo ukTimeZone = TimeZoneInfo.FindSystemTimeZoneById(ukTimeZoneId);

        // 10/26/2014 1:00:00 AM (This is meant to be BST, not GMT)
        DateTime ambiguousUkDateTime = new DateTime(2014, 10, 26, 1, 0, 0);

        // 10/26/2014 1:00:00 AM (UTC)
        DateTime ambiguousUkDateTimeUtc = TimeZoneInfo.ConvertTimeToUtc(ambiguousUkDateTime, ukTimeZone);

        // 10/26/2014 1:00:00 AM (WHAT?)
        DateTime backToUkTime = TimeZoneInfo.ConvertTimeFromUtc(ambiguousUkDateTimeUtc, ukTimeZone);
    }
编辑2
为了更具体地回答我的问题:根据我上面的示例,您将如何在数据存储系统中存储2014年10月26日凌晨1:00(这是一个不明确的时间)并在.NET应用程序中读取/写入此数据?

您可以在应用程序中使用UTC时间。UTC时间没有夏令时,所以它是完全线性的


通过将时间存储为UTC,应用程序将始终准确地知道时间的含义。您可以将时间转换为本地时间以显示给用户,这自然意味着当夏令时发生变化时,他们会看到时间的间隔或重叠,但在幕后,您的应用程序仍然确切地知道时间是什么。

如何存储时间在很大程度上取决于上下文。特别是,存储某件事情发生的时间(过去时态或现在时态)与存储某件事情将要或应该发生的时间(将来时态)是不同的问题

过去/现在

对于过去或现在的事件,您可以在
日期时间偏移量
或基于UTC的
日期时间
之间进行选择。虽然两者都表示一个明确的时间点,
DateTimeOffset
也将跟踪本地时间值。这有助于了解记录时间戳的时间是早上还是晚上。如果您不关心这些事情,请使用基于UTC的
DateTime
。(更多信息请参阅)

“全球持续,局部显示”这句格言适用于过去/现在的事件。可以将时间戳转换为用户的本地时区,也可以将其转换为所需的任何时区。当查看器的上下文不一定与记录时间的上下文相同时,这会很有帮助

以航空公司为例:

  • 您可以将航班从伦敦起飞的时间记录为
    2014-10-26T01:00:00+01:00
    DateTimeOffset
    。正如你所指出的,由于天气原因,这一天一点钟的时间会重复。但是由于我们记录了偏移量,我们知道这是第一次发生在01:00

  • 我们还可以将此时刻记录为
    2014-10-26T00:00:00Z
    的基于UTC的
    DateTime
    。唯一丢失的信息是一天中的实际本地时间

  • 如果我们(单独)知道数据来自
    “欧洲/伦敦”
    时区(或者使用ID
    “GMT标准时间”
    ,如果您使用的是
    时区信息
    ),那么我们可以肯定地说,这一时间是在英国夏令时(UTC+01:00)而不是在格林尼治时间(UTC+00:00)

  • 假设飞行持续7小时,在纽约降落。那将是
    2014-10-26T07:00:00Z
    。它也可以用
    2014-10-26T08:00:00+01:00
    DateTimeOffset
    表示,但该偏移不适用于纽约。因此,我们应用目标时区
    “America/New_York”
    (或ID“Eastern Standard time”和
    TimeZoneInfo
    )并获得
    2014-10-26T03:00:00-04:00Z
    。你现在知道航班在纽约当地时间凌晨3点降落

未来

由于以下几个原因,未来事件要复杂得多:

  • 你不一定知道偏移量是多少。根据目前已知的时区规则,你只知道你认为它会是什么。一些政府会在很短的时间内更改时区偏移量或DST规则,这并不总是允许系统有时间进行更新。在调度系统中,掌握时区更新是绝对关键的,而且很容易被忽略

  • UTC无法安排大多数人为事件,尤其是重复事件。想象一个每天早上7点叫醒你的闹钟。如果您按UTC进行计划,则在转换后,它将在6:00或8:00开始运行(取决于您进行原始转换的时间以及您处理的是春季转换还是秋季转换)

    • 这是个例外。如果事件遵循“每x小时”(或更小)等规则,则您可以按UTC进行安排,而不会出现问题。不过要小心,像“每周三x小时”这样的规则不符合这一例外,因为即使决定是否是周三也涉及时区。

  • 最好的办法是在星期五之前安排未来的活动
        static void ConvertToAndFromUtcWrongly()
        {
            const string ukTimeZoneId = "GMT Standard Time";
            TimeZoneInfo ukTimeZone = TimeZoneInfo.FindSystemTimeZoneById(ukTimeZoneId);
    
            // 10/26/2014 1:00:00 AM (This is meant to be BST, not GMT)
            DateTime ambiguousUkDateTime = new DateTime(2014, 10, 26, 1, 0, 0);
    
            // 10/26/2014 1:00:00 AM (UTC)
            DateTime ambiguousUkDateTimeUtc = TimeZoneInfo.ConvertTimeToUtc(ambiguousUkDateTime, ukTimeZone);
    
            // 10/26/2014 1:00:00 AM (WHAT?)
            DateTime backToUkTime = TimeZoneInfo.ConvertTimeFromUtc(ambiguousUkDateTimeUtc, ukTimeZone);
        }