我们正在处理一个需要处理来自不同时区和夏令时设置的全球时间数据的应用程序。这个想法是在内部以 UTC 格式存储所有内容,并且只为本地化的用户界面来回转换。SQL Server 是否提供任何机制来处理给定时间、国家和时区的翻译?
这一定是一个普遍的问题,所以我很惊讶谷歌不会出现任何可用的东西。
任何指针?
我们正在处理一个需要处理来自不同时区和夏令时设置的全球时间数据的应用程序。这个想法是在内部以 UTC 格式存储所有内容,并且只为本地化的用户界面来回转换。SQL Server 是否提供任何机制来处理给定时间、国家和时区的翻译?
这一定是一个普遍的问题,所以我很惊讶谷歌不会出现任何可用的东西。
任何指针?
这适用于当前与 SQL Server 主机具有相同 UTC 偏移量的日期;它不考虑夏令时的变化。替换YOUR_DATE
为要转换的本地日期。
SELECT DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), YOUR_DATE);
7 年过去了……
实际上,这个新的 SQL Server 2016 功能可以满足您的需求。
它被称为 AT TIME ZONE,它考虑 DST(夏令时)的变化将日期转换为指定的时区。
更多信息在这里:
https ://msdn.microsoft.com/en-us/library/mt612795.aspx
虽然其中一些答案会让您大致了解,但由于夏令时,您无法对 SqlServer 2005 及更早版本的任意日期执行您尝试执行的操作。使用当前本地和当前 UTC 之间的差异将为我提供今天存在的偏移量。我还没有找到一种方法来确定相关日期的偏移量。
也就是说,我知道 SqlServer 2008 提供了一些新的日期函数可以解决这个问题,但是使用早期版本的人需要注意这些限制。
我们的方法是保持 UTC 并在客户端执行转换,我们可以更好地控制转换的准确性。
对于 SQL Server 2016 和更高版本以及 Azure SQL 数据库,请使用内置AT TIME ZONE
语句。
对于旧版本的 SQL Server,您可以使用我的SQL Server 时区支持项目在 IANA 标准时区之间进行转换,如此处所列。
UTC 到本地是这样的:
SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles')
UTC的本地是这样的:
SELECT Tzdb.LocalToUtc('2015-07-01 00:00:00', 'America/Los_Angeles', 1, 1)
当本地时间值受夏令时影响时,数字选项是用于控制行为的标志。这些在项目的文档中有详细描述。
这是将一个区域转换DateTime
为另一个区域的代码DateTime
DECLARE @UTCDateTime DATETIME = GETUTCDATE();
DECLARE @ConvertedZoneDateTime DATETIME;
-- 'UTC' to 'India Standard Time' DATETIME
SET @ConvertedZoneDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE 'India Standard Time'
SELECT @UTCDateTime AS UTCDATE,@ConvertedZoneDateTime AS IndiaStandardTime
-- 'India Standard Time' to 'UTC' DATETIME
SET @UTCDateTime = @ConvertedZoneDateTime AT TIME ZONE 'India Standard Time' AT TIME ZONE 'UTC'
SELECT @ConvertedZoneDateTime AS IndiaStandardTime,@UTCDateTime AS UTCDATE
注意:AT TIME ZONE
仅适用于 SQL Server 2016+,优点是在转换为特定时区时会自动考虑夏令时
SQL Server 2008 有一个名为datetimeoffset
. 这对这种类型的东西非常有用。
http://msdn.microsoft.com/en-us/library/bb630289.aspx
然后您可以使用该函数SWITCHOFFSET
将其从一个时区移动到另一个时区,但仍保持相同的 UTC 值。
http://msdn.microsoft.com/en-us/library/bb677244.aspx
抢
我倾向于将 DateTimeOffset 用于与本地事件无关的所有日期时间存储(即:会议/派对等,12pm-3pm 在博物馆)。
将当前 DTO 获取为 UTC:
DECLARE @utcNow DATETIMEOFFSET = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME())
DECLARE @utcToday DATE = CONVERT(DATE, @utcNow);
DECLARE @utcTomorrow DATE = DATEADD(D, 1, @utcNow);
SELECT @utcToday [today]
,@utcTomorrow [tomorrow]
,@utcNow [utcNow]
注意:通过网络发送时,我将始终使用 UTC……客户端 JS 可以轻松地往返本地 UTC。见:new Date().toJSON()
...
以下 JS 将处理将 ISO8601 格式的 UTC/GMT 日期解析为本地日期时间。
if (typeof Date.fromISOString != 'function') {
//method to handle conversion from an ISO-8601 style string to a Date object
// Date.fromISOString("2009-07-03T16:09:45Z")
// Fri Jul 03 2009 09:09:45 GMT-0700
Date.fromISOString = function(input) {
var date = new Date(input); //EcmaScript5 includes ISO-8601 style parsing
if (!isNaN(date)) return date;
//early shorting of invalid input
if (typeof input !== "string" || input.length < 10 || input.length > 40) return null;
var iso8601Format = /^(\d{4})-(\d{2})-(\d{2})((([T ](\d{2}):(\d{2})(:(\d{2})(\.(\d{1,12}))?)?)?)?)?([Zz]|([-+])(\d{2})\:?(\d{2}))?$/;
//normalize input
var input = input.toString().replace(/^\s+/,'').replace(/\s+$/,'');
if (!iso8601Format.test(input))
return null; //invalid format
var d = input.match(iso8601Format);
var offset = 0;
date = new Date(+d[1], +d[2]-1, +d[3], +d[7] || 0, +d[8] || 0, +d[10] || 0, Math.round(+("0." + (d[12] || 0)) * 1000));
//use specified offset
if (d[13] == 'Z') offset = 0-date.getTimezoneOffset();
else if (d[13]) offset = ((parseInt(d[15],10) * 60) + (parseInt(d[16],10)) * ((d[14] == '-') ? 1 : -1)) - date.getTimezoneOffset();
date.setTime(date.getTime() + (offset * 60000));
if (date.getTime() <= new Date(-62135571600000).getTime()) // CLR DateTime.MinValue
return null;
return date;
};
}
是的,在某种程度上如此详细。
我使用的方法(2008 年之前)是在插入数据库之前在 .NET 业务逻辑中进行转换。
您可以使用 GETUTCDATE() 函数来获取 UTC 日期时间 可能您可以选择 GETUTCDATE() 和 GETDATE() 之间的差异,并使用此差异将您的日期调整为 UTC
但我同意之前的消息,即在业务层(例如在 .NET 中)控制正确的日期时间要容易得多。
SUBSTRING(CONVERT(VARCHAR(34), SYSDATETIMEOFFSET()), 29, 5)
返回(例如):
-06:0
不是 100% 肯定的,这将永远有效。
示例用法:
SELECT
Getdate=GETDATE()
,SysDateTimeOffset=SYSDATETIMEOFFSET()
,SWITCHOFFSET=SWITCHOFFSET(SYSDATETIMEOFFSET(),0)
,GetutcDate=GETUTCDATE()
GO
回报:
Getdate SysDateTimeOffset SWITCHOFFSET GetutcDate
2013-12-06 15:54:55.373 2013-12-06 15:54:55.3765498 -08:00 2013-12-06 23:54:55.3765498 +00:00 2013-12-06 23:54:55.373