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



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

我有一个情况,我的数据都存储在UTC。我需要通过确定某个当地时间,比方说8点,是UTC时间,来对那个数据进行比较。本地时间的时区将逐行变化。(存储了每行的时区,因此这不是问题。)那个特定的当地时间与日期没有关联。一直都是"8am"

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

但是现在我有点卡住了。

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

这是鸡生蛋还是蛋生鸡的问题。

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

想法?

这里确实存在歧义问题,但这不是鸡生蛋还是蛋生鸡的问题。

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

暂时把时区、DST和UTC的问题放在一边。如果我问你,"现在离早上8点还有几个小时?"你可以给我两个不同的答案。现在是晚上7点,所以你可以说"11个小时"——因为这是我们从今天早上8点开始的时间。但我也可以说"13个小时"——因为这是我们从明天早上8点开始的时间。在这个非常简单的例子中,你可以用两种不同的方法来消除歧义。你可以说"最后一个8AM"或"下一个8AM"。或者你可以说"无论今天发生了什么"。

现在回到UTC的概念。什么是"UTC日"?我们知道是24小时,因为UTC不遵循夏令时。但说它运行"午夜到午夜UTC",并不是一个很有意义的措施。当然,有一些地方使用这个定义(例如,StackOverflow的统计引擎)。但是对于大多数人来说,我们认为"今天"是我们自己当地的时间。

所以我真的不能说"无论早上8点发生今天"。唯一的日期度量方法是UTC日期。你不知道你应该看哪个当地日期。让我们看一个真实的例子:

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

现在我把这个时间记录在数据库中,然后我问:

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

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

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

另一种方法是使用您正在比较的UTC时间,找出您今天所在的本地。因此,在上面的示例中,亚利桑那州的本地June 14从6月13日17:00 UTC运行到6月14日17:00 UTC。

所以总结一下,你想知道"夏令时的上午8点是否围绕这个UTC日期时间?",如果没有更多的信息,你无法回答这个问题,要么是8点的日期,要么是一些逻辑关系,其中有几个选项可用。选择一个适合你需要的策略。

你在评论中问:

我怎么知道如果现在在UTC是在dst在X时区,所以我可以相应地调整?

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

那么,让我们假设我住在纽约市。查看本网站,我们知道EDT于2013年3月10日当地时间凌晨2点生效,并将于2013年11月3日当地时间凌晨2点恢复为EST。

所以我们有以下内容:

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是日光偏移量,而夏令时应该在当地时间两点结束。我们有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]

…那些是按钮,如果你看不出来的话。:)

相关内容

  • 没有找到相关文章

最新更新