很遗憾,SQL Server 没有任何内置的时区转换功能。但是,这可以通过 SQLCLR 完成。您可以使用DateTime.ToLocalTime() 方法创建标量用户定义函数。
是的,从技术上讲,您可以使用具有 ConvertTime(DateTime, TimeZoneInfo, TimeZoneInfo) 和 ConvertTimeFromUtc(DateTime, TimeZoneInfo) 等方法的 TimeZoneInfo 类,但 TimeZoneInfo 类要求程序集具有 PERMISSION_SET 或 UNSAFE,而 DateTime可以以SAFE 运行。坚持使用DateTime 方法的唯一缺点是它们只能在UTC 和服务器的本地时间之间转换,而TimeZoneInfo 可以在任何两个给定时区之间转换。
由于您的数据已经采用 GMT / UTC,使用DateTime.ToLocalTime 转换为太平洋* 时间会相当容易,但只有在您更改服务器的时区之前 更新数据,而不是之后(如问题中所述)。此时您可以执行以下操作:
ALTER TABLE [SchemaName].[TableName]
ADD [IsConverted] BIT NULL; -- make sure we don't convert multiple times
WHILE (1 = 1)
BEGIN
UPDATE TOP (2000) tab
SET tab.DateField = dbo.ConvertTimeToLocalTime(tab.DateField),
tab.IsConverted = 1
FROM [SchemaName].[TableName] tab
WHERE tab.IsConverted IS NULL;
IF (@@ROWCOUNT = 0)
BEGIN
BREAK;
END;
END;
-- Remove the temporary tracking field, but not until all rows are converted
IF (NOT EXISTS(
SELECT *
FROM [SchemaName].[TableName] tab
WHERE tab.IsConverted IS NULL
)
)
BEGIN
ALTER TABLE [SchemaName].[TableName]
DROP COLUMN [IsConverted];
END;
* 请注意,我使用“太平洋”时间而不是 PST,因为太平洋时间可以是 PST 或 PDT,具体取决于夏令时。因此,尝试通过简单地执行 DATEADD(HOUR, -7, [DateField]) 进行转换对于某些行是正确的,但不是所有行。
另外,对于那些对这个特殊转换函数感兴趣的人,它可以在SQL# 库的完整版(我是它的作者)中获得(虽然不是免费的)。周围有一些博客文章展示了如何做到这一点,尽管我还没有看到一个遵循最佳实践的博客文章,以便它能够以最佳方式运行。当然,如果这是一次性转换,那么对于价格而言,最佳性能显然不如低效率但免费重要:-)。