【问题标题】:TSQL Convert DateTime & Timezone Offset (in Minutes) to another Time ZoneT SQL 将日期时间和时区偏移量(以分钟为单位)转换为另一个时区
【发布时间】:2015-09-09 20:01:31
【问题描述】:

在我的 SQL Server 2008 R2 数据库中,我有一个 LastHWScan 列 (datetime) 和一个 TimzoneOffset 列 (int)。

LastHWScan 列存储正在扫描的工作站本地的datetimeTimezoneOffset 列将时区偏移存储为正数或负数分钟数。达拉斯是 -300,布加勒斯特是 180。

如何在 SQL 查询中将这些 datetime 从各个时区转换为达拉斯时间?

将所有内容都转换为 UTC,然后再转换为达拉斯时间会更容易吗?

【问题讨论】:

  • 我想出了如何在 Excel 中做到这一点,并且我已经接近在 TSQL 中重现该过程,但我还没有完全做到。我正在做 DATEADD(minute,((-300 - W.TimezoneOffset) * (-1 * SIGN(W.TimezoneOffset))), W.LastHWSCan。我在 excel 中通过反复试验确定的标志的业务。如果两个时区偏移的符号不一样,我需要更改分钟数的符号来调整时间。这在 excel 中有效,但在 SQL 中并非在所有情况下都有效。

标签: sql-server tsql datetime timezone


【解决方案1】:

在我的 SQL Server 2008 R2 数据库中,我有一个 LastHWScan 字段(日期时间)和一个 TimzoneOffset 字段(整数)。

没关系,尽管您可能还认为 SQL Server 有一个 datetimeoffset 字段,可以将这些字段组合成一个类型。

或者,如果时区偏移对您的方案不重要,您可以考虑将等效的 UTC 值仅存储在 datetimedatetime2 字段中。

LastHWScan 字段存储被扫描工作站的本地日期时间。 TimezoneOffset 字段将时区偏移存储为正数或负数分钟数。达拉斯是 -300,布加勒斯特是 180。

这里要小心。偏移量应与特定日期和时间对齐。夏季 DST 生效时,达拉斯可能是 -300 (UTC-5),但一年中的大部分时间是 -360 (UTC-6)。同样,布加勒斯特在 180 (UTC+3) 和 120 (UTC+2) 之间交替。

不要将偏移量与日期/时间分开,或假设一个位置和日期/时间的偏移量对该位置内所有可能的其他日期/时间值都有效。

如何在 SQL 查询中将这些日期时间从不同时区转换为达拉斯时间?

这在 SQL 中很难做到,因为您必须考虑达拉斯的夏令时规则。其他 DB 有 CONVERT_TZ 之类的函数,但 SQL Server 没有内置这样的函数。您可以编写自己的函数,或者您可以考虑我的 SQL Server Time Zone Support 项目。

将所有内容都转换为 UTC,然后再转换为达拉斯时间会更容易吗?

“更容易”是主观的。许多人更喜欢以 UTC 存储值。将它们存储在datetimeoffset(或像您所做的那样在两个字段中)很好 - 当本地时间在应用程序域的上下文中很重要时(参见DateTime vs DateTimeOffset),这是更可取的。唯一不应该做的就是删除偏移量并仅存储本地时间。

即使您确实转换为 UTC,也无助于转换。尽管您已经正确识别了特定时间点,但您仍然必须考虑目标时区的时区规则。如果您只需要美国中部时间,您可以考虑将转换规则和偏移量硬编码到 UDF 或存储过程中。否则,将我的时区集成项目与 "America/Chicago" 时区 id 一起使用。

例子:

SELECT Tzdb.UtcToLocal(dateadd(mi, -offset, localdatetime), 'America/Chicago')

在调用自定义 UDF 之前,请注意从本地转换回 UTC 的偏移量的否定。

【讨论】:

  • OP 指定 SQL Server 2008 R2。
  • 我将查看 SQL Server 时区支持项目。这可能会解决许多问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-08
  • 2012-08-02
  • 2020-01-26
  • 1970-01-01
  • 2011-04-23
  • 1970-01-01
相关资源
最近更新 更多