3

使用 SQL Server 2008+。SQLCLR 不是一个选项。

我有一种情况,我的数据全部存储在 UTC 中。我需要通过确定某个当地时间(比如说上午 8 点)在 UTC 中与该数据进行比较。当地时间的时区将逐行变化。(存储了每一行的时区,所以这不是问题。)某个本地时间没有与之关联的日期。它总是只是“早上 8 点”。

我在数据库中有时区数据,如果时区遵循夏令时,这也会告诉我基本 UTC 偏移量。

但现在我有点卡住了。

我的问题是,为了进行夏令时调整,我需要知道特定时区的当前日期/时间是否在特定范围内,但我只能转换为适当的本地时间来检查我是否知道如果是夏令时!换句话说,除非我知道UTC偏移量是否因夏令时而关闭,否则我如何检查它是否是夏令时?

这是一个先有鸡还是先有蛋的问题。

在我看来,唯一的解决方案是能够有一个表格来计算每个时区的夏令时感知偏移量。

想法?

4

1 回答 1

1

你在这里确实有一个模棱两可的问题,但这不是先有鸡还是先有蛋的问题。

您缺少的信息是“什么定义了一天?” 我知道,这听起来很疯狂,但“一天”并不是一个普遍的概念。这是一个本地的。

只需一分钟,抛开时区、DST 和 UTC 的问题。如果我问你,“我们现在离早上 8 点还有多少小时?” 你可以给我两个不同的答案。现在是晚上 7 点,所以您可能会说“11 小时”——因为这是我们从今天早上 8 点开始的时间。但我也可以说“13 小时”——因为那是我们从明天早上 8 点开始的时间。现在在这个非常简单的示例中,您可以通过两种不同的方式之一来消除歧义。您可能会说“最后一个早上 8 点”或“下一个早上 8 点”。或者你可以说“无论今天发生什么” 。

现在回到UTC的概念。什么是“UTC 日”?好吧,我们知道它是 24 小时,因为 UTC 不遵循任何夏令时。但是说它运行“午夜到午夜 UTC”并不是一个非常有意义的衡量标准。当然,有些地方使用了这个定义(例如,StackOverflow 的统计引擎)。但对于大多数人来说,我们想到的是我们自己当地时间的“今天”。

所以我真的不能说“无论今天上午 8 点发生了什么”。您拥有的唯一日期测量是 UTC 日期。您将不知道应该查看哪个本地日期。让我们举一个真实的例子:

  • 我住在亚利桑那州凤凰城,所以我的时区偏移量是 UTC-7。我们这里没有夏令时。
  • 现在是当地时间 2013 年 6 月 14 日晚上 7 点。
  • 那是 2013 年 6 月 15 日,世界标准时间凌晨 2 点。

现在我把那个时间记录在数据库里,后来我问:

  • “我们离亚利桑那时间早上 8 点还有多远?”
  • 根据我掌握的信息,我不知道我应该寻找 6 月 14 日上午 8 点还是 6 月 15 日上午 8 点。只有后者属于同一 UTC 日期,但我当然可能对其中任何一个感兴趣。

如果您可以在业务逻辑中决定一次还是一次,那么您可以解决这个问题。只需将 UTC 日期时间转换为本地时区。然后向前或向后滚动到所需时间。如果您的时区有 DST,并且您在此过程中跨越了过渡日期,则可以对此进行调整。

您也可以选择两者中最近的时间,但这当然取决于您的业务逻辑。

另一种方法是使用您要比较的 UTC 时间来确定您今天所在的本地。所以在我上面的例子中,亚利桑那州当地的6 月 14 日从 6 月 13 日 17:00 UTC 到 6 月 14 日 17:00 UTC。

总而言之,您想知道“DST 中的上午 8 点围绕这个 UTC 日期时间吗?”,如果没有更多信息,您无法回答这个问题,无论是上午 8 点的日期,还是要遵循的一些逻辑关系,其中有几个选项可用。选择适合您需求的策略。

更新

你在评论中问:

我怎么知道现在 UTC 是否在 X 时区的 dst 中,以便我可以相应地调整?

这是datetimeoffset类型可以提供帮助的地方。您不仅想跟踪“DST 是否有效”,还想跟踪目标时区的精确偏移量,包括任何可能有效的 DST。区别是微妙的,但它归结为跟踪一个完整的偏移量,而不仅仅是一个布尔值是/否。

所以,让我们假设我住在纽约市。查看该网站,我们知道美国东部时间于当地时间 2013 年 3 月 10 日凌晨 2 点生效,并将于当地时间 2013 年 11 月 3 日凌晨 2 点恢复到美国东部标准时间。

所以我们有以下内容:

UTC                     Local datetimeofffset              
2013-03-10T05:00:00Z    2013-03-10T00:00:00-05:00    
2013-03-10T06:00:00Z    2013-03-10T01:00:00-05:00    
2013-03-10T07:00:00Z    2013-03-10T03:00:00-04:00  <--- transition
2013-03-10T08:00:00Z    2013-03-10T04:00:00-04:00
...
2013-11-03T04:00:00Z    2013-11-03T00:00:00-04:00
2013-11-03T05:00:00Z    2013-11-03T01:00:00-04:00
2013-11-03T06:00:00Z    2013-11-03T01:00:00-05:00  <--- transition
2013-11-03T07:00:00Z    2013-11-03T02:00:00-05:00

现在请注意,如果去掉偏移量,则只有一个单向函数。换句话说,您始终可以为 UTC 时间确定正确的本地时间,但除非您知道回退转换期间的偏移量(或者除非您愿意忍受歧义),否则您不能朝另一个方向发展。

所以从UTC到本地时间的算法应该是这样的:

  1. 从 UTC 日期时间开始: 2013-11-03T05:30:00Z
  2. 应用标准偏移 (-5) 2013-11-03T00:30:00-05:00
  3. 应用采光偏移 (-4) 2013-11-03T01:30:00-04:00
  4. 根据时区规则,哪一个是有效的?
    • 在这种情况下,日光偏移是有效的。
    • 您的时区数据应该包含这些信息。
    • 如果不是,那么您需要重新考虑时区表的来源。

让我们在另一个 1:30 时间再试一次:

  1. 从 UTC 日期时间开始: 2013-11-03T06:30:00Z
  2. 应用标准偏移 (-5) 2013-11-03T01:30:00-05:00
  3. 应用采光偏移 (-4) 2013-11-03T02:30:00-04:00
  4. 根据时区规则,哪一个是有效的?
    • 在这种情况下,标准偏移量是有效的。
    • 我们怎么知道?因为 -4 是日光偏移,并且 DST 应该在当地时间 2:00 结束。我们有 2:30 本地时间与该偏移量相关联,因此只有标准时间在该时区有效。

那么你可以从UTC转换为本地吗?是的。总是。

但是您还说另一列中的本地值就像8AM. 因此,如果是1:30AM,那么您肯定会在回退过渡期间产生歧义。没有办法解决这个问题,只能选择一个。

有时,您可能只想选择其中一个,但有时您可能想出错。有时您可能希望让您的用户选择他们感兴趣的两个中的哪一个。看到如下对话框并非闻所未闻:

DAYLIGHT SAVING TIME
We're sorry, but there are two different instances of 1:30 AM on this day.
Which did you mean?

        [1:30 AM Eastern Daylight Time]     [1:30 AM Eastern Standard Time]

...那些是按钮,如果你不知道的话。:)

于 2013-06-15T02:41:13.217 回答