我正在做一些SQL选择查询,并希望将我的UTC日期时间列转换为本地时间,以便在我的查询结果中显示为本地时间。注意,我不希望通过代码进行这种转换,而是当我对我的数据库进行手动和随机SQL查询时。


当前回答

对于Azure SQL和@@Version >= SQL Server 2016用户,下面是一个使用AT TIME ZONE的简单函数。

CREATE FUNCTION [dbo].[Global_Convert_UTCTimeTo_LocalTime]
(
   @LocalTimeZone        VARCHAR(50),
   @UTCDateTime          DATETIME
)
RETURNS DATETIME
AS
BEGIN
   DECLARE @ConvertedDateTime DATETIME;

   SELECT @ConvertedDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE @LocalTimeZone
   RETURN @ConvertedDateTime

END
GO

对于@LocalTimeZone可以采用的值类型,请转到此链接或转到KEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones

其他回答

对于Azure SQL和@@Version >= SQL Server 2016用户,下面是一个使用AT TIME ZONE的简单函数。

CREATE FUNCTION [dbo].[Global_Convert_UTCTimeTo_LocalTime]
(
   @LocalTimeZone        VARCHAR(50),
   @UTCDateTime          DATETIME
)
RETURNS DATETIME
AS
BEGIN
   DECLARE @ConvertedDateTime DATETIME;

   SELECT @ConvertedDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE @LocalTimeZone
   RETURN @ConvertedDateTime

END
GO

对于@LocalTimeZone可以采用的值类型,请转到此链接或转到KEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones

如果在数据库上启用CLR以及使用sql server的时区是一个选项,那么可以很容易地在. net中编写它。

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime fn_GetLocalFromUTC(SqlDateTime UTC)
    {
        if (UTC.IsNull)
            return UTC;

        return new SqlDateTime(UTC.Value.ToLocalTime());
    }
}

输入一个UTC日期时间值,然后输出相对于服务器的本地日期时间值。Null值返回Null。

UNIX时间戳只是一个特定日期和UNIX纪元之间的秒数,

SELECT DATEDIFF(SECOND,{d '1970-01-01'},GETDATE()) //返回SQL server中的UNIX时间戳

你可以创建一个函数,使用Country Offset将本地日期时间转换为Unix UTC SQL server中的Unix时间戳函数

对于任何仍然试图解决这个问题的人,这里有一个在SQL Server 2017中工作的概念证明

 declare
    @StartDate date = '2020-01-01'

;with cte_utc as
(
    select 
         1 as i
        ,CONVERT(datetime, @StartDate) AS UTC
        ,datepart(weekday, CONVERT(datetime, @StartDate)) as Weekday
        ,datepart(month, CONVERT(datetime, @StartDate)) as [Month]
        ,datepart(YEAR, CONVERT(datetime, @StartDate)) as [Year]
        
    union all

    Select
         i + 1
        ,dateadd(d, 1, utc)
        ,datepart(weekday, CONVERT(datetime, dateadd(d, 1, utc))) as Weekday
        ,datepart(month, CONVERT(datetime, dateadd(d, 1, utc))) as [Month]
        ,datepart(YEAR, CONVERT(datetime, dateadd(d, 1, utc))) as [Year]
    from    
        cte_utc
    where
        (i + 1) < 32767

), cte_utc_dates as 
(
    select 
        *,
        DENSE_RANK()OVER(PARTITION BY [Year], [Month], [Weekday] ORDER BY Utc) WeekDayIndex
    from
        cte_utc

), cte_hours as (
    select 0 as [Hour]
    union all
    select [Hour] + 1 from cte_hours where [Hour] < 23
)

select
    d.*
    , DATEADD(hour, h.Hour, d.UTC) AS UtcTime
    ,CONVERT(datetime, DATEADD(hour, h.Hour, d.UTC) AT TIME ZONE 'UTC' AT TIME ZONE 'Central Standard Time') CST
    ,CONVERT(datetime, DATEADD(hour, h.Hour, d.UTC) AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time') EST
from
    cte_utc_dates d, cte_hours h
where
    ([Month] = 3 and [Weekday] = 1 and WeekDayIndex = 2 )-- dst start
    or 
    ([Month] = 11 and [Weekday] = 1 and WeekDayIndex = 1 )-- dst end
order by
    utc
OPTION (MAXRECURSION 32767)

GO

我有代码执行UTC到本地和本地到UTC时间,允许使用这样的代码进行转换

DECLARE @usersTimezone VARCHAR(32)='Europe/London'
DECLARE @utcDT DATETIME=GetUTCDate()
DECLARE @userDT DATETIME=[dbo].[funcUTCtoLocal](@utcDT, @usersTimezone)

and

DECLARE @usersTimezone VARCHAR(32)='Europe/London'
DECLARE @userDT DATETIME=GetDate()
DECLARE @utcDT DATETIME=[dbo].[funcLocaltoUTC](@userDT, @usersTimezone)

这些函数可以支持NodaTime提供的IANA/TZDB中的全部或一部分时区-请参阅https://nodatime.org/TimeZones上的完整列表

请注意,我的用例意味着我只需要一个“当前”窗口,允许在大约+/- 5年的范围内转换时间。这意味着,如果您需要很宽的时间段,我使用的方法可能不适合您,因为它在给定日期范围内为每个时区间隔生成代码的方式不同。

该项目位于GitHub: https://github.com/elliveny/SQLServerTimeConversion

这将生成如下示例所示的SQL函数代码