使用聚合功能将UTC时间转换为SQL Server 2014中的本地时间

问题描述:

问题:需要查询从世界不同地区收集的大量时间序列数据以生成不同的报告。使用聚合功能将UTC时间转换为SQL Server 2014中的本地时间

时间序列表看起来像这样:LoggerId(INT),日期时间(日期时间)值(十进制)。

日期时间以UTC存储,但它们需要转换为当地时间。在某些情况下,数据需要使用AVG,SUM把事情像每天/每周/每月平均总等

用户可以更改在任何时候在他们的报告中使用的数据的时区进行汇总。例如,用户A可以决定在时区A中看到记录器#1的数据,并且用户B可以选择在时区B中看到相同的数据。

到目前为止,由于夏令时,我无法在SQL Server 2014中找到一个好的解决方案这使事情变得复杂。我知道,在SQL Server二零一六年,是一种新的“在时区”功能,这可能是我需要什么,但它不提供2014年

任何帮助将不胜感激。

下面是一些示例数据:

LoggerId,DatetimeUTC,价值

1,2017年4月10日10:00:00,10

1,2017年4月10日11:00:00,20

1,2017年4月10日12:00:00,30

1,2017年4月10日13:00:00,40


从查询的预期结果,显示每日总记录器1的NZ时间(UTC + 12):

LoggerId,DatetimeLocal,价值

1,2017年4月10日,30

1,2017年4月11日,70

+0

,发布您的示例数据和预期输出 – Mansoor

+0

我有si将问题简化为一点,并添加一些示例数据。谢谢。 – Robert

+0

您是否需要正确考虑DST? –

对低于回DST功能的外观,你可以修改按您的要求。你只需传递utc日期时间和偏移量。 :

Create FUNCTION [dbo].[UDTToLocalTime_Test](@UDT AS DATETIME,@offs as SMALLINT) 
RETURNS DATETIME 
AS 
BEGIN 
--==================================================== 
--Set the Timezone Offset (NOT During DST [Daylight Saving Time]) 
--==================================================== 
DECLARE @Offset AS SMALLINT 
SET @Offset = @offs 
--==================================================== 
--Figure out the Offset Datetime 
--==================================================== 
DECLARE @LocalDate AS DATETIME 
SET @LocalDate = DATEADD(hh, @Offset, @UDT) 
--==================================================== 
--Figure out the DST Offset for the UDT Datetime 
--==================================================== 
DECLARE @DaylightSavingOffset AS SMALLINT 
DECLARE @Year as SMALLINT 
DECLARE @DSTStartDate AS DATETIME 
DECLARE @DSTEndDate AS DATETIME 
--Get Year 
SET @Year = YEAR(@LocalDate) 
--Get First Possible DST StartDay 
IF (@Year > 2006) SET @DSTStartDate = CAST(@Year AS CHAR(4)) + '-03-08 02:00:00' 
ELSE SET @DSTStartDate = CAST(@Year AS CHAR(4)) + '-04-01 02:00:00' 
--Get DST StartDate 
WHILE (DATENAME(dw, @DSTStartDate) <> 'sunday') SET @DSTStartDate = DATEADD(day, 1,@DSTStartDate) 
--Get First Possible DST EndDate 
IF (@Year > 2006) SET @DSTEndDate = CAST(@Year AS CHAR(4)) + '-11-01 02:00:00' 
ELSE SET @DSTEndDate = CAST(@Year AS CHAR(4)) + '-10-25 02:00:00' 
--Get DST EndDate 
WHILE (DATENAME(dw, @DSTEndDate) <> 'sunday') SET @DSTEndDate = DATEADD(day,1,@DSTEndDate) 
--Get DaylightSavingOffset 
SET @DaylightSavingOffset = CASE WHEN @LocalDate BETWEEN @DSTStartDate AND @DSTEndDate THEN 1 ELSE 0 END 
--==================================================== 
--Finally add the DST Offset 
--==================================================== 
RETURN DATEADD(hh, @DaylightSavingOffset, @LocalDate) 
END 

只需要调用,如:

select [dbo].[UDTToLocalTime_Test](getutcdate(),+4) as DateSTim 

很久以前我就发现这个解决方案,并为我的情景做工精细希望它也将帮助你。

+0

这似乎是基于某种切换实现了两套DST规则,但我不确定这适用于哪个国家/地区。这听起来像OP需要与多个时区一起工作,因此,如果您要走这条路线,您需要实施*所有国家/地区的规则,其中一些规则不可能适用于未来。另外,假定'DATENAME'正在返回英文,这绝不是给定的。 –

+0

感谢您的解决方案。是否有一种很好的方法可以自动为不同国家维护时区规则? DST的一个问题是他们似乎一直在改变。我的另一个担心是解决方案的性能。首先需要做一些基准测试。 – Robert

如果你不介意使用不安全的CLR组件在数据库中,那么你可以简单地写自己的.NET CLR标量函数来执行转换为您服务。以下是Dicko2的GitHub项目的链接。0演示了如何实现自己的CLR:

https://github.com/HostedSolutions/SQLDates

以下OneDrive链接包含完整的上述CLR项目安装脚本:

SQLDatesFunc

下面是对一个例子使用该组件:

DECLARE @utcDateTime DATETIME = GETUTCDATE(); 

DECLARE @cstDateTime DATETIME; 
DECLARE @estDateTime DATETIME; 

SET @cstDateTime = [dbo].[ConvertToLocalTimeZone]('Central Standard Time', @utcDateTime); 
SET @estDateTime = [dbo].[ConvertToLocalTimeZone]('Eastern Standard Time', @utcDateTime); 

SELECT @cstDateTime AS CST, @estDateTime AS EST; 
+0

谢谢。我也在考虑CLR方法。我以前没有用过,所以需要做一些调查。我主要担心的是它的性能与SQL以及它将如何整合到我们当前的开发环境中。 – Robert

+0

@Robert不用担心,就性能而言,CLR选项将超越在SQL Server中创建的任何自定义UDF,并将为您处理所有边界情况(如DST)。我自己的测试表明,在一百万条记录上调用该函数只会使查询速度下降大约一秒。关于集成,您只需要运行我提供的脚本(它将为您创建并安装程序集,而无需编译)。 –