T-SQL:将datetime字段的值从UTC转换为CET时区

时间:2014-09-29 13:32:04

标签: sql sql-server datetime

我有一个数据库,它将日期存储为具有UTC偏移的日期时间。 如何将这些日期从UTC转换为在select语句中说出CET?

是否有某种语法糖可以照顾整个白天的秋/冬和春/夏偏移的东西?

修改: 我在CodePlex上发现了this库非常有用:

  

DateTimeUtil

     

用于扩展日期时间处理的一组UDF和配置数据,例如: G。它提供简单的时区转换,包括。使用本机T-SQL(无CLR)支持夏令时。

3 个答案:

答案 0 :(得分:1)

SELECT CONVERT(VARCHAR, dbo.udfToLocalTime(t.CreatedDateTime, '1'), 113)
FROM yourtable t 

如果有更新:

UPDATE yourtable t 
SET t.CreatedDateTime = CONVERT(VARCHAR, dbo.udfToLocalTime(t.CreatedDateTime, '1'), 113)

使用如下的UDF

CREATE FUNCTION udfToLocalTime
(
   @UtcDateTimeAS DATETIME
   ,@UtcOffset AS INT = -8 --PST
)
RETURNS DATETIME
AS 
BEGIN

    DECLARE @PstDateTimeAS DATETIME
            ,@Year  AS CHAR(4)
            ,@DstStart  AS DATETIME
            ,@DstEndAS DATETIME
            ,@Mar1  AS DATETIME
            ,@Nov1  AS DATETIME
            ,@MarTime   AS TIME
            ,@NovTime   AS TIME
            ,@Mar1Day   AS INT
            ,@Nov1Day   AS INT
            ,@MarDiff   AS INT
            ,@NovDiff   AS INT

    SELECT  @Year   = YEAR(@UtcDateTime)
            ,@MarTime   = CONVERT(TIME, DATEADD(HOUR, -@UtcOffset, '1900-01-01 02:00'))
            ,@NovTime   = CONVERT(TIME, DATEADD(HOUR, -@UtcOffset - 1, '1900-01-01 02:00'))
            ,@Mar1  = CONVERT(CHAR(16), @Year + '-03-01 ' + CONVERT(CHAR(5), @MarTime), 126)
            ,@Nov1  = CONVERT(CHAR(16), @Year + '-11-01 ' + CONVERT(CHAR(5), @NovTime), 126)
            ,@Mar1Day   = DATEPART(WEEKDAY, @Mar1)
            ,@Nov1Day   = DATEPART(WEEKDAY, @Nov1)

    --Get number of days between Mar 1 and DST start date
    IF @Mar1Day = 1 
    SET @MarDiff = 7
    ELSE 
    SET @MarDiff = 15 - @Mar1Day

    --Get number of days between Nov 1 and DST end date
    IF @Nov1Day = 1 
    SET @NovDiff = 0
    ELSE 
    SET @NovDiff = 8 - @Nov1Day

    --Get DST start and end dates
    SELECT @DstStart   = DATEADD(DAY, @MarDiff, @Mar1)
            ,@DstEnd= DATEADD(DAY, @NovDiff, @Nov1)

    --Change UTC offset if @UtcDateTime is in DST Range
    IF @UtcDateTime >= @DstStart AND @UtcDateTime < @DstEnd 
    SET @UtcOffset = @UtcOffset + 1

    --Get Conversion
    SET @PstDateTime = DATEADD(HOUR, @UtcOffset, @UtcDateTime)
    RETURN @PstDateTime
END

答案 1 :(得分:0)

如果您的数据库包含UTC日期,那将是完美的。更好的方法是使用您的操作系统时区偏移量。

例如:

select
  dateadd(minute,DATEPART(TZ, SYSDATETIMEOFFSET()), YourUTCDate) as timestamp
from YourTable

答案 2 :(得分:0)

使用以下函数转换日期时间区域。

create or replace FUNCTION timezoneConverter 
(v_date in date, inputDateZone in varchar2 default 'UTC', outputDateZone in varchar2 default 'UTC')
return date AS date_out date;
BEGIN
    SELECT
        to_date(
            to_char(FROM_TZ(to_timestamp(to_char( v_date,'dd.mm.yyyy hh24:mi:ss' ),'dd.mm.yyyy hh24:mi:ss'),
        to_char(inputDateZone)) AT TIME ZONE
        to_char(outputDateZone),
        'dd.mm.yyyy hh24:mi:ss'), 'dd.mm.yyyy hh24:mi:ss')
    into date_out FROM dual;
    return date_out;
EXCEPTION
    when others then
        DBMS_OUTPUT.put_line('Date:' || v_date || 'TZ:' || inputDateZone || '-' || outputDateZone || ' / ' || sqlcode || ' / ' || SQLERRM(sqlcode));
        --date_out := to_date(to_char(v_date-1/24, 'yyyymmddhh24miss'), 'yyyymmddhh24miss');
        date_out := null;
        return date_out;
END;
/

DayLight 中欧时间 (CET) 与中欧夏令时间 (CEST)

Short Hour 跳过第二个小时。 Note: hours shift because clocks change forward 1 hour.

--set serveroutput on; -- View -> Dbms Output : set serveroutput on [serveroutput must be set ON or OFF or OPTIMIZED or UNOPTIMIZED]
SELECT
 timezoneConverter(to_timestamp('2020-03-29T01:00Z', 'yyyy-mm-dd"T"hh24:mi"Z"'), 'CET', 'UTC') CETtoUTC1, -- 29-MAR-2020 00:00:00
 timezoneConverter(to_timestamp('2020-03-29T02:00Z', 'yyyy-mm-dd"T"hh24:mi"Z"'), 'CET', 'UTC') CETtoUTC2, -- (null)
 timezoneConverter(to_timestamp('2020-03-29T02:00Z', 'yyyy-mm-dd"T"hh24:mi"Z"'), 'UTC', 'CET') UTCtoCET FROM dual; -- 29-MAR-2020 04:00:00

-- Date:29-MAR-2020 02:00:00TZ:CET-UTC / -1878 / ORA-01878: specified field not found in datetime or interval

Long Hour 第二个小时重复 Note: hours shift because clocks change backward 1 hour.

SELECT
 timezoneConverter(to_timestamp('2020-10-25T02:00Z', 'yyyy-mm-dd"T"hh24:mi"Z"'), 'UTC', 'CET') UTCtoCET, -- 25-OCT-2020 03:00:00
 timezoneConverter(to_timestamp('2020-10-25T02:00Z', 'yyyy-mm-dd"T"hh24:mi"Z"'), 'CET', 'UTC') CETtoUTC2, -- 25-OCT-2020 01:00:00
 timezoneConverter(to_timestamp('2020-10-25T01:00Z', 'yyyy-mm-dd"T"hh24:mi"Z"'), 'CET', 'UTC') CETtoUTC1 FROM dual; -- 24-OCT-2020 23:00:00

以下示例将一个时区的日期时间值转换为另一个时区:docs.oracle.com

SELECT FROM_TZ(CAST(TO_DATE('1999-12-01 11:00:00', 
      'YYYY-MM-DD HH:MI:SS') AS TIMESTAMP), 'America/New_York') 
   AT TIME ZONE 'America/Los_Angeles' "West Coast Time" 
   FROM DUAL;

West Coast Time
------------------------------------------------
01-DEC-99 08.00.00.000000 AM AMERICA/LOS_ANGELES