关于tsql:获取SQL Server中特定时区的本地日期/时间

Getting a local date/time for a specific timezone in SQL Server

使用SQL Server 2008+。sqlcr不是选项。

我有一种情况,所有数据都存储在UTC中。我需要通过确定某个特定的当地时间,比如说上午8点,用UTC来比较这些数据。本地时间的时区将逐行变化。(存储了每行的时区,所以这不是问题。)某些本地时间没有与之相关的日期。总是"早上8点"。

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

但现在我有点困了。

我的问题是,为了进行夏令时调整,我需要知道特定时区中的当前日期/时间是否在某些范围内,但我只能转换到适当的本地时间来进行检查,如果我知道是否是夏令时!换言之,除非我知道UTC偏移是否由于日光节约而关闭,否则如何检查是否为日光节约?

这是鸡和蛋的问题。

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

思想?


你确实有一个模棱两可的问题,但这不是鸡和蛋的问题。好的。

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

只需一分钟,就可以将时区、DST和UTC的问题放在一边。如果我问你,"现在8点以外我们还有多少小时?"你可以给我两个不同的答案。现在是晚上7点,所以你可能会说"11个小时",因为这就是我们今天早上8点的时间。但我也可以说"13小时"——因为这就是我们明天早上8点开始的时间。现在在这个非常简单的示例中,您可以用两种不同的方法之一消除歧义。你可以说"最后8点"或"下一个8点"。或者你可以说"不管今天发生了什么。"好的。

现在回到UTC的概念。什么是"UTC日"?嗯,我们知道现在是24小时,因为UTC不遵循任何夏令时。但是说它运行"从午夜到午夜UTC",并不是一个非常有意义的度量。当然,也有一些地方使用这个定义(例如,stackoverflow的stats引擎)。但对大多数人来说,我们在当地时间想到"今天"。好的。

所以我不能说"今天早上8点左右"。唯一的日期度量是UTC日期。你不知道该看哪一个当地的日期。让我们举一个真正的例子:好的。

  • 我住在亚利桑那州的凤凰城,所以我的时区偏移是UTC-7。我们这里没有DST。
  • 目前是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。好的。

总而言之,您想知道"在这个UTC日期时间周围的DST中是上午8点吗?"如果没有更多的信息,你不能回答这个问题,要么是上午8点的日期,要么是一些逻辑关系,其中有几个选项可用。选择一个适合你需要的策略。好的。

更新好的。

你在评论中问过:好的。

How can I know if right now in UTC is in dst in X time zone so I can adjust accordingly?

Ok.

这是datetimeoffset类型可以帮助的地方。您不仅要跟踪"DST有效",还需要跟踪目标时区的精确偏移量,包括任何可能有效的DST。这种差异是微妙的,但归根结底是跟踪一个完整的偏移量,而不仅仅是一个布尔值的是/否。好的。

所以,让我们假装我住在纽约市。查看此站点,我们知道EDT于2013年3月10日当地时间凌晨2点生效,将于2013年11月3日当地时间凌晨2点返回EST。好的。

所以我们有以下内容:好的。

1
2
3
4
5
6
7
8
9
10
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到当地时间的算法应该是这样的:好的。

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

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

    但您也说过,另一列中的本地值类似于8AM。因此,如果是1:30AM,那么在回退过渡期间肯定会有一个模糊性。除了选择一个,没有办法解决这个问题。好的。

    有时,您可能只想选择其中一个,但有时您可能想出错。有时你可能想让你的用户选择他们感兴趣的两个。看到下面这样的对话并非闻所未闻:好的。

    1
    2
    3
    4
    5
    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]

    …如果你不知道,那是按钮。:)好的。好啊。