Chuyển đổi cột Ngày tháng từ UTC sang giờ địa phương trong câu lệnh chọn


208

Tôi đang thực hiện một vài truy vấn chọn SQL và muốn chuyển đổi cột thời gian UTC của mình thành giờ địa phương để được hiển thị dưới dạng giờ địa phương trong kết quả truy vấn của tôi. Lưu ý, tôi KHÔNG tìm cách thực hiện chuyển đổi này thông qua mã mà là khi tôi thực hiện các truy vấn SQL thủ công và ngẫu nhiên đối với cơ sở dữ liệu của mình.


Câu hỏi này có vẻ giống với hoàn cảnh của bạn không? stackoverflow.com/questions/3404646/
hy

Câu trả lời:


321

Bạn có thể làm điều này như sau trên SQL Server 2008 hoặc cao hơn:

SELECT CONVERT(datetime, 
               SWITCHOFFSET(CONVERT(datetimeoffset, 
                                    MyTable.UtcColumn), 
                            DATENAME(TzOffset, SYSDATETIMEOFFSET()))) 
       AS ColumnInLocalTime
FROM MyTable

Bạn cũng có thể thực hiện ít dài dòng hơn:

SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), MyTable.UtcColumn) 
       AS ColumnInLocalTime
FROM MyTable

Dù bạn làm gì, đừng sử dụng -để trừ ngày, vì hoạt động không phải là nguyên tử và đôi khi bạn sẽ nhận được kết quả không xác định do điều kiện cuộc đua giữa thời gian hệ thống và thời gian địa phương được kiểm tra tại các thời điểm khác nhau (ví dụ, không phải nguyên tử) .

Xin lưu ý rằng câu trả lời này không đưa DST vào tài khoản. Nếu bạn muốn bao gồm điều chỉnh DST, vui lòng xem câu hỏi SO sau:

Cách tạo chức năng Bắt đầu và Kết thúc tiết kiệm ánh sáng ban ngày trong SQL Server


38
Có cách nào để tạo tài khoản này để tiết kiệm ánh sáng ban ngày không?
Steve

15
Tôi không thấy tên của múi giờ ở đây nên điều này không chính xác. Thật là một ý tưởng tồi khi cho rằng bạn có thể chuyển đổi sang giờ địa phương bằng cách thực hiện số học
JonnyRaa

7
@MichaelGoldshteyn nếu bạn có bù múi giờ, bạn vẫn không biết múi giờ logic là gì. Múi giờ là những thứ xã hội và có thể được chính phủ thay đổi ở các điểm khác nhau. Phần bù cho múi giờ có thể khác nhau ở các thời điểm / lịch sử khác nhau (thời gian mùa hè là thời điểm chung). Bạn đang bù đắp một khoảng thời gian bằng phần bù hiện tại từ UTC ... một điểm nữa là điều này sẽ cung cấp múi giờ của máy chủ chứ không phải máy khách, điều này có thể là vấn đề nữa nếu bạn đang lưu trữ ở một quốc gia khác.
JonnyRaa

4
@Niloofar Câu trả lời đơn giản là bạn không nên và không nên. Dữ liệu phải luôn được lưu trữ trong UTC (tốt nhất là dựa trên đồng hồ của máy chủ cơ sở dữ liệu, không phải máy chủ web, máy chủ ứng dụng và chắc chắn không phải đồng hồ của máy khách). Hiển thị datetime đó là một chức năng cho lớp UI và nó chịu trách nhiệm chuyển đổi datetime thành định dạng bạn muốn (bao gồm cả múi giờ nếu cần thiết).
Robert McKee

11
Đối với bất kỳ ai sử dụng sql azure, phương pháp này sẽ không hiệu quả vì các hàm ngày / giờ đều trả về UTC, do đó, việc so sánh GETDATE () với GETUTCDATE () không mang lại cho bạn bất cứ điều gì để làm việc và kết quả của bạn giống như bạn đã bắt đầu.
Brian Surowiec

59

Tôi không thấy bất kỳ ví dụ nào hữu ích trong việc lấy một datetime được lưu dưới dạng UTC thành datetime trong một múi giờ được chỉ định (KHÔNG phải múi giờ của máy chủ vì cơ sở dữ liệu Azure SQL chạy dưới dạng UTC). Đây là cách tôi xử lý nó. Nó không thanh lịch nhưng nó đơn giản và cung cấp cho bạn câu trả lời đúng mà không cần duy trì các bảng khác:

select CONVERT(datetime, SWITCHOFFSET(dateTimeField, DATEPART(TZOFFSET, 
dateTimeField AT TIME ZONE 'Eastern Standard Time')))

4
Chỉ hoạt động cho năm 2016 và sử dụng đăng ký hệ thống. Nhưng giải pháp tuyệt vời cho Azure.
Dan Cundy

2
Cái này hoạt động cho thời gian xanh được lưu trữ trong UTC, cảm ơn các bạn
Null

3
Dưới đây là danh sách các chuỗi bạn có thể sử dụng cho các múi giờ: stackoverflow.com/a/7908482/631277
Matt Kemp

1
Nếu sử dụng SQL 2016 và AT TIME ZONEcú pháp, hãy xem xét stackoverflow.com/a/44941536/112764 - bạn có thể xâu chuỗi nhiều chuyển đổi lại với nhau bằng cách ghép nhiều at time zone <blah>s.
NateJ

3
Điều này cũng hơi kỳ quặc, nhưng một số thử nghiệm rất cơ bản có vẻ như điều này cũng có thể hoạt động - dateTimeField AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time'- chỉ cần xâu chuỗi các AT TIME ZONEtuyên bố. (@NateJ đã đề cập đến vấn đề này ở trên tôi thấy ngay bây giờ)
David Mohundro

22

Nếu thời gian ngày địa phương của bạn là nói Eastern Standard Timevà bạn muốn chuyển đổi từ UTC sang đó, thì trong Azure SQL và SQL Server 2016 trở lên, bạn có thể làm:

SELECT YourUtcColumn AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time' AS
       LocalTime
FROM   YourTable

Danh sách đầy đủ các tên múi giờ có thể được tìm thấy với:

SELECT * FROM sys.time_zone_info 

Và vâng, các múi giờ được đặt tên xấu - mặc dù vậy Eastern Standard Time, tiết kiệm ánh sáng ban ngày được tính đến.


2
Các múi giờ và độ lệch cũng có thể được tìm thấy trong SQL Server tại đây: CHỌN * TỪ sys.time_zone_info
rayzinnz

21

Nếu bạn cần một chuyển đổi khác ngoài vị trí máy chủ của mình, đây là chức năng cho phép bạn vượt qua một khoản bù tiêu chuẩn và tài khoản cho Thời báo tiết kiệm ánh sáng ban ngày của Hoa Kỳ:

-- =============================================
-- Author:      Ron Smith
-- Create date: 2013-10-23
-- Description: Converts UTC to DST
--              based on passed Standard offset
-- =============================================
CREATE FUNCTION [dbo].[fn_UTC_to_DST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

    declare 
        @DST datetime,
        @SSM datetime, -- Second Sunday in March
        @FSN datetime  -- First Sunday in November

    -- get DST Range
    set @SSM = datename(year,@UTC) + '0314' 
    set @SSM = dateadd(hour,2,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))
    set @FSN = datename(year,@UTC) + '1107'
    set @FSN = dateadd(second,-1,dateadd(hour,2,dateadd(day,datepart(dw,@FSN)*-1+1,@FSN)))

    -- add an hour to @StandardOffset if @UTC is in DST range
    if @UTC between @SSM and @FSN
        set @StandardOffset = @StandardOffset + 1

    -- convert to DST
    set @DST = dateadd(hour,@StandardOffset,@UTC)

    -- return converted datetime
    return @DST

END

GO

2
Ron Smith Tôi biết đây là một bài viết cũ nhưng tôi đã tò mò những gì mã hóa cứng '0314' và '1107' đại diện cho việc nhận được phạm vi DST. Nó dường như là những ngày được mã hóa cứng thay đổi do DTS. Tại sao bạn lại cứng mã này khi nó phải là một ngày được tính toán vì ngày thay đổi dựa trên nơi trên lịch vào ngày Chủ nhật thứ hai của tháng ba và Chủ nhật đầu tiên của tháng 11 rơi. Những ngày mã hóa cứng sẽ làm cho mã này về cơ bản là thiếu sót.
Mike

2
Câu hỏi hay :) Đó là những ngày tối đa trong đó Chủ nhật thứ hai của tháng 3 và Chủ nhật đầu tiên của tháng 11 có thể xảy ra. Các dòng sau thiết lập các biến thành ngày thực tế.
Ron Smith

8

Sử dụng các cơ hội SQL Server 2016 mới:

CREATE FUNCTION ToLocalTime(@dtUtc datetime, @timezoneId nvarchar(256))
RETURNS datetime
AS BEGIN

return @dtUtc AT TIME ZONE 'UTC' AT TIME ZONE @timezoneId

/* -- second way, faster

return SWITCHOFFSET(@dtUtc , DATENAME(tz, @dtUtc AT TIME ZONE @timezoneId))

*/

/* -- third way

declare @dtLocal datetimeoffset
set @dtLocal = @dtUtc AT TIME ZONE @timezoneId
return dateadd(minute, DATEPART (TZoffset, @dtLocal), @dtUtc)

*/

END
GO

Nhưng thủ tục clr hoạt động nhanh hơn 5 lần: '- (

Hãy chú ý rằng Offset cho một TimeZone có thể thay đổi thành thời gian mùa đông hoặc mùa hè. Ví dụ

select cast('2017-02-08 09:00:00.000' as datetime) AT TIME ZONE 'Eastern Standard Time'
select cast('2017-08-08 09:00:00.000' as datetime) AT TIME ZONE 'Eastern Standard Time'

các kết quả:

2017-02-08 09:00:00.000 -05:00
2017-08-08 09:00:00.000 -04:00

Bạn không thể chỉ cần thêm bù liên tục.


5

Nếu bật CLR trên cơ sở dữ liệu của bạn là một tùy chọn cũng như sử dụng múi giờ của máy chủ sql, thì nó có thể được viết bằng .Net khá dễ dàng.

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());
    }
}

Giá trị thời gian UTC đi vào và giá trị thời gian cục bộ liên quan đến máy chủ xuất hiện. Giá trị Null trả về null.


5

Không có cách đơn giản để làm điều này một cách chính xác VÀ chung chung.

Trước hết phải hiểu rằng phần bù phụ thuộc vào ngày được đề cập, Múi giờ VÀ DST. GetDate()-GetUTCDatechỉ cung cấp cho bạn phần bù vào ngày hôm nay tại TZ của máy chủ, không liên quan.

Tôi chỉ thấy hai giải pháp làm việc và tôi đã tìm kiếm rất nhiều.

1) Hàm SQL tùy chỉnh với một vài bảng dữ liệu cơ sở như Vùng thời gian và quy tắc DST trên TZ. Làm việc nhưng không thanh lịch lắm. Tôi không thể đăng nó vì tôi không sở hữu mã.

EDIT: Dưới đây là một ví dụ về phương pháp này https://gist.github.com/drumsta/16b79cee6bc195cd89c8

2) Thêm một cụm .net vào db, .Net có thể thực hiện việc này rất dễ dàng. Điều này đang hoạt động rất tốt nhưng nhược điểm là bạn cần cấu hình một vài tham số ở cấp độ máy chủ và cấu hình dễ bị hỏng, ví dụ nếu bạn khôi phục cơ sở dữ liệu. Tôi sử dụng phương pháp này nhưng tôi không thể đăng nó vì tôi không sở hữu mã.


4

Không ai trong số này làm việc cho tôi nhưng điều này dưới đây hoạt động 100%. Hy vọng điều này có thể giúp những người khác đang cố gắng chuyển đổi nó như tôi.

CREATE FUNCTION [dbo].[fn_UTC_to_EST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

declare 
    @DST datetime,
    @SSM datetime, -- Second Sunday in March
    @FSN datetime  -- First Sunday in November
-- get DST Range
set @SSM = DATEADD(dd,7 + (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))+'02:00:00' 
set @FSN = DATEADD(dd, (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0)) +'02:00:00'

-- add an hour to @StandardOffset if @UTC is in DST range
if @UTC between @SSM and @FSN
    set @StandardOffset = @StandardOffset + 1

-- convert to DST
set @DST = dateadd(hour,@StandardOffset,@UTC)

-- return converted datetime
return @DST

END

1
Đây phải là câu trả lời được chấp nhận. Điều duy nhất tôi sẽ thay đổi là tên vì nó ngụ ý là giờ EST, khi thực sự nó là Giờ địa phương và StandardPackset được truyền dưới dạng tham số.
Greg Gum

Đồng ý, câu trả lời hay nhất ... nhưng thay vì phải vượt qua phần bù như một tham số, tôi đã thêm phần này vào trong thân hàm:declare @StandardOffset int = datediff (hh, GETUTCDATE(), GETDATE())
Tom Warfield

Theo dõi tình trạng trước đây của tôi - Nếu bạn tính toán @St Chuẩn Offerset, thì bạn không cần thực hiện chỉnh sửa DST.
Tom Warfield

3

Đây là phiên bản dành cho tiết kiệm ánh sáng ban ngày, bù UTC và không bị khóa trong một năm cụ thể.

---------------------------------------------------------------------------------------------------
--Name:     udfToLocalTime.sql
--Purpose:  To convert UTC to local US time accounting for DST
--Author:   Patrick Slesicki
--Date:     3/25/2014
--Notes:    Works on SQL Server 2008R2 and later, maybe SQL Server 2008 as well.
--          Good only for US States observing the Energy Policy Act of 2005.
--          Function doesn't apply for years prior to 2007.
--          Function assumes that the 1st day of the week is Sunday.
--Tests:        
--          SELECT dbo.udfToLocalTime('2014-03-09 9:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-03-09 10:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-11-02 8:00', DEFAULT)
--          SELECT dbo.udfToLocalTime('2014-11-02 9:00', DEFAULT)
---------------------------------------------------------------------------------------------------
ALTER FUNCTION udfToLocalTime
    (
    @UtcDateTime    AS DATETIME
    ,@UtcOffset     AS INT = -8 --PST
    )
RETURNS DATETIME
AS 
BEGIN
    DECLARE 
        @PstDateTime    AS DATETIME
        ,@Year          AS CHAR(4)
        ,@DstStart      AS DATETIME
        ,@DstEnd        AS 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
GO

3

Tôi thấy cách tắt chức năng là quá chậm khi có nhiều dữ liệu. Vì vậy, tôi đã làm điều đó thông qua việc tham gia vào một hàm bảng cho phép tính toán chênh lệch giờ. Về cơ bản, đó là các phân đoạn datetime với giờ bù. Một năm sẽ là 4 hàng. Vì vậy, chức năng bảng

dbo.fn_getTimeZoneOffsets('3/1/2007 7:00am', '11/5/2007 9:00am', 'EPT')

sẽ trả lại bảng này:

startTime          endTime   offset  isHr2
3/1/07 7:00     3/11/07 6:59    -5    0
3/11/07 7:00    11/4/07 6:59    -4    0
11/4/07 7:00    11/4/07 7:59    -5    1
11/4/07 8:00    11/5/07 9:00    -5    0

Nó không tiết kiệm ánh sáng ban ngày. Dưới đây là một ví dụ về cách sử dụng nó và bài viết blog đầy đủ ở đây .

select mt.startTime as startUTC, 
    dateadd(hh, tzStart.offset, mt.startTime) as startLocal, 
    tzStart.isHr2
from MyTable mt 
inner join dbo.fn_getTimeZoneOffsets(@startViewUTC, @endViewUTC, @timeZone)  tzStart
on mt.startTime between tzStart.startTime and tzStart.endTime

Nó không xuất hiện để xem xét DST một cách chính xác. Không chắc chắn nếu bạn cho rằng chỉ có Hoa Kỳ tồn tại và các quy tắc DST không bao giờ thay đổi.
vikjon0

@ vikjon0 có, dự án tôi xây dựng này chỉ có múi giờ ở Hoa Kỳ.
JBrooks

2
 declare @mydate2 datetime
 set @mydate2=Getdate()
 select @mydate2 as mydate,
 dateadd(minute, datediff(minute,getdate(),@mydate2),getutcdate())

1

Câu trả lời của Ron có lỗi. Nó sử dụng 2:00 AM giờ địa phương nơi yêu cầu tương đương UTC. Tôi không có đủ điểm danh tiếng để nhận xét về câu trả lời của Ron để phiên bản sửa lỗi xuất hiện bên dưới:

-- =============================================
-- Author:      Ron Smith
-- Create date: 2013-10-23
-- Description: Converts UTC to DST
--              based on passed Standard offset
-- =============================================
CREATE FUNCTION [dbo].[fn_UTC_to_DST]
(
    @UTC datetime,
    @StandardOffset int
)
RETURNS datetime
AS
BEGIN

declare 
    @DST datetime,
    @SSM datetime, -- Second Sunday in March
    @FSN datetime  -- First Sunday in November
-- get DST Range
set @SSM = datename(year,@UTC) + '0314' 
set @SSM = dateadd(hour,2 - @StandardOffset,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))
set @FSN = datename(year,@UTC) + '1107'
set @FSN = dateadd(second,-1,dateadd(hour,2 - (@StandardOffset + 1),dateadd(day,datepart(dw,@FSN)*-1+1,@FSN)))

-- add an hour to @StandardOffset if @UTC is in DST range
if @UTC between @SSM and @FSN
    set @StandardOffset = @StandardOffset + 1

-- convert to DST
set @DST = dateadd(hour,@StandardOffset,@UTC)

-- return converted datetime
return @DST

END

Đây là một tính năng, không phải là lỗi :) Hầu hết Hoa Kỳ bắt đầu Giờ tiết kiệm ánh sáng ban ngày lúc 2:00 sáng en.wikipedia.org/wiki/Daylight_saving_time
Ron Smith

@RonSmith Có, lúc 2:00 sáng giờ địa phương, chúng tôi phải chuyển đổi sang UTC để phát hiện xem thời gian UTC đã cho có nằm trong phạm vi DST hay không.
jlspublic

1

Dấu thời gian UNIX chỉ là số giây giữa một ngày cụ thể và Epoch Unix,

CHỌN DATEDIFF (THỨ HAI, {d '1970-01-01'}, GETDATE ()) // Điều này sẽ trả về dấu thời gian UNIX trong máy chủ SQL

bạn có thể tạo một hàm cho thời gian ngày cục bộ sang chuyển đổi UTC Unix bằng cách sử dụng Hàm bù trừ quốc gia sang Dấu thời gian Unix Trong máy chủ SQL


1

Thật đơn giản. Hãy thử điều này cho Azure SQL Server:

SELECT YourDateTimeColumn AT TIME ZONE 'Eastern Standard Time' FROM YourTable

Đối với máy chủ SQL cục bộ:

SELECT CONVERT(datetime2, SWITCHOFFSET(CONVERT(datetimeoffset, gETDATE()), DATENAME(TzOffset, gETDATE() AT TIME ZONE 'Eastern Standard Time'))) FROM YourTable

1
Điều gì xảy ra với điều này trong thời gian tiết kiệm ánh sáng ban ngày (vì múi giờ nói cụ thể là "Giờ chuẩn miền đông")?
Đánh dấu

1

Đối với người dùng Azure SQL và @@Version> = SQL Server 2016, Dưới đây là một chức năng đơn giản sử dụng 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

Đối với các loại giá trị @LocalTimeZonecó thể mất, vui lòng truy cập liên kết này hoặc Chuyển đếnKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones


0

Như một cảnh báo - nếu bạn sẽ sử dụng những điều sau đây (lưu ý mili giây thay vì phút):

    SELECT DATEADD(ms, DATEDIFF(ms, GETUTCDATE(), GETDATE()), MyTable.UtcColumn) 
    AS ColumnInLocalTime
    FROM MyTable

Hãy nhớ rằng phần DATEDIFF sẽ không luôn trả về cùng một số. Vì vậy, đừng sử dụng nó để so sánh DateTimes xuống đến mili giây.


0

Tôi đã thấy rằng chức năng này nhanh hơn các giải pháp khác bằng cách sử dụng một bảng hoặc vòng lặp riêng biệt. Nó chỉ là một tuyên bố trường hợp cơ bản. Cho rằng tất cả các tháng trong khoảng từ tháng 4 đến tháng 10 có thời gian bù -4 giờ (Giờ phương Đông), chúng ta chỉ cần thêm một vài dòng trường hợp cho các ngày rìa. Mặt khác, độ lệch là -5 giờ.

Điều này đặc trưng cho việc chuyển đổi từ UTC sang giờ phương Đông, nhưng các chức năng múi giờ bổ sung có thể được thêm vào khi cần thiết.

USE [YourDatabaseName]
GO

/****** Object:  UserDefinedFunction [dbo].[ConvertUTCtoEastern]    Script Date: 11/2/2016 5:21:52 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


CREATE FUNCTION [dbo].[ConvertUTCtoEastern]
(
@dtStartDate DATETIME
)
RETURNS DATETIME
AS
BEGIN
DECLARE @Working DATETIME
DECLARE @Returned DATETIME

SET @Working = @dtStartDate
SET @Working = 
case when month(@Working) between 4 and 10 then dateadd(HH,-4,@Working) 
     when @Working between '2017-03-12' and '2017-11-05' then dateadd(HH,-4,@Working) 
     when @Working between '2016-03-13' and '2016-11-06' then dateadd(HH,-4,@Working) 
     when @Working between '2015-03-08' and '2015-11-01' then dateadd(HH,-4,@Working) 
     when @Working between '2014-03-09' and '2014-11-02' then dateadd(HH,-4,@Working) 
     when @Working between '2013-03-10' and '2013-11-03' then dateadd(HH,-4,@Working) 
     when @Working between '2012-03-11' and '2012-11-04' then dateadd(HH,-4,@Working) 
else dateadd(HH,-5,@Working) end

SET @Returned = @Working

RETURN @Returned

END


GO

0

Điều này sẽ có thể có được thời gian máy chủ với DST

declare @dt datetime
set @dt = getutcdate() -- GMT equivalent

sysdatetimeoffset đưa DST vào tài khoản

select [InputTime] = @dt
       , [LocalTime2] = dateadd(mi, datediff(mi, sysdatetimeoffset(),getdate()), @dt) 

0

Hàm đầu tiên: được định cấu hình cho múi giờ tiếng Ý (+1, +2), ngày chuyển đổi: chủ nhật cuối cùng của tháng ba và tháng mười, trả về sự khác biệt giữa múi giờ hiện tại và thời gian làm tham số.

Returns:
current timezone < parameter timezone ==> +1
current timezone > parameter timezone ==> -1
else 0

Mã này là:

CREATE FUNCTION [dbo].[UF_ADJUST_OFFSET]
(
    @dt_utc datetime2(7)
)
RETURNS INT
AS
BEGIN


declare @month int,
        @year int,
        @current_offset int,
        @offset_since int,
        @offset int,
        @yearmonth varchar(8),
        @changeoffsetdate datetime2(7)

declare @lastweek table(giorno datetime2(7))

select @current_offset = DATEDIFF(hh, GETUTCDATE(), GETDATE())

select @month = datepart(month, @dt_utc)

if @month < 3 or @month > 10 Begin Set @offset_since = 1 Goto JMP End

if @month > 3 and @month < 10 Begin Set @offset_since = 2 Goto JMP End

--If i'm here is march or october
select @year = datepart(yyyy, @dt_utc)

if @month = 3
Begin

Set @yearmonth = cast(@year as varchar) + '-03-'

Insert Into @lastweek Values(@yearmonth + '31 03:00:00.000000'),(@yearmonth + '30 03:00:00.000000'),(@yearmonth + '29 03:00:00.000000'),(@yearmonth + '28 03:00:00.000000'),
                         (@yearmonth + '27 03:00:00.000000'),(@yearmonth + '26 03:00:00.000000'),(@yearmonth + '25 03:00:00.000000')

--Last week of march
Select @changeoffsetdate = giorno From @lastweek Where  datepart(weekday, giorno) = 1

    if @dt_utc < @changeoffsetdate 
    Begin 
        Set @offset_since = 1 
    End Else Begin
        Set @offset_since = 2
    End
End

if @month = 10
Begin

Set @yearmonth = cast(@year as varchar) + '-10-'

Insert Into @lastweek Values(@yearmonth + '31 03:00:00.000000'),(@yearmonth + '30 03:00:00.000000'),(@yearmonth + '29 03:00:00.000000'),(@yearmonth + '28 03:00:00.000000'),
                         (@yearmonth + '27 03:00:00.000000'),(@yearmonth + '26 03:00:00.000000'),(@yearmonth + '25 03:00:00.000000')

--Last week of october
Select @changeoffsetdate = giorno From @lastweek Where  datepart(weekday, giorno) = 1

    if @dt_utc > @changeoffsetdate 
    Begin 
        Set @offset_since = 1 
    End Else Begin
        Set @offset_since = 2
    End
End

JMP:

if @current_offset < @offset_since Begin
    Set @offset = 1
End Else if @current_offset > @offset_since Set @offset = -1 Else Set @offset = 0

Return @offset

END

Sau đó, chức năng chuyển đổi ngày

CREATE FUNCTION [dbo].[UF_CONVERT]
(
    @dt_utc datetime2(7)
)
RETURNS datetime
AS
BEGIN

    declare @offset int


    Select @offset = dbo.UF_ADJUST_OFFSET(@dt_utc)

    if @dt_utc >= '9999-12-31 22:59:59.9999999'
        set @dt_utc = '9999-12-31 23:59:59.9999999'
    Else
        set @dt_utc = (SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), @dt_utc) )

    if @offset <> 0
        Set @dt_utc = dateadd(hh, @offset, @dt_utc)

    RETURN @dt_utc

END

0

- có được thời gian tiêu chuẩn Ấn Độ từ utc

CREATE FUNCTION dbo.getISTTime
(
@UTCDate datetime
)
RETURNS datetime
AS
BEGIN

    RETURN dateadd(minute,330,@UTCDate)

END
GO

0

Điều này có thể được thực hiện mà không có chức năng. Mã dưới đây sẽ chuyển đổi thời gian UTC sang kế toán giờ miền núi để tiết kiệm ánh sáng ban ngày. Điều chỉnh tất cả các số -6 và -7 theo múi giờ của bạn tương ứng (nghĩa là đối với EST, bạn sẽ điều chỉnh thành -4 và -5 tương ứng)

--Adjust a UTC value, in the example the UTC field is identified as UTC.Field, to account for daylight savings time when converting out of UTC to Mountain time.
CASE
    --When it's between March and November, it is summer time which is -6 from UTC
    WHEN MONTH ( UTC.Field ) > 3 AND MONTH ( UTC.Field ) < 11 
        THEN DATEADD ( HOUR , -6 , UTC.Field )
    --When its March and the day is greater than the 14, you know it's summer (-6)
    WHEN MONTH ( UTC.Field ) = 3
        AND DATEPART ( DAY , UTC.Field ) >= 14 
        THEN
            --However, if UTC is before 9am on that Sunday, then it's before 2am Mountain which means it's still Winter daylight time.
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '9:00'
                    --Before 2am mountain time so it's winter, -7 hours for Winter daylight time
                    THEN DATEADD ( HOUR , -7 , UTC.Field )
                --Otherwise -6 because it'll be after 2am making it Summer daylight time
                ELSE DATEADD ( HOUR , -6 , UTC.Field )
            END
    WHEN MONTH ( UTC.Field ) = 3
        AND ( DATEPART ( WEEKDAY , UTC.Field ) + 7 ) <= DATEPART ( day , UTC.Field ) 
        THEN 
            --According to the date, it's moved onto Summer daylight, but we need to account for the hours leading up to 2am if it's Sunday
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '9:00'
                    --Before 9am UTC is before 2am Mountain so it's winter Daylight, -7 hours
                    THEN DATEADD ( HOUR , -7 , UTC.Field )
                --Otherwise, it's summer daylight, -6 hours
                ELSE DATEADD ( HOUR , -6 , UTC.Field )
            END
    --When it's November and the weekday is greater than the calendar date, it's still Summer so -6 from the time
    WHEN MONTH ( UTC.Field ) = 11
        AND DATEPART ( WEEKDAY , UTC.Field ) > DATEPART ( DAY , UTC.Field ) 
        THEN DATEADD ( HOUR , -6 , UTC.Field )
    WHEN MONTH ( UTC.Field ) = 11
        AND DATEPART ( WEEKDAY , UTC.Field ) <= DATEPART ( DAY , UTC.Field ) 
            --If the weekday is less than or equal to the calendar day it's Winter daylight but we need to account for the hours leading up to 2am.
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '8:00'
                    --If it's before 8am UTC and it's Sunday in the logic outlined, then it's still Summer daylight, -6 hours
                    THEN DATEADD ( HOUR , -6 , UTC.Field )
                --Otherwise, adjust for Winter daylight at -7
                ELSE DATEADD ( HOUR , -7 , UTC.Field )
            END
    --If the date doesn't fall into any of the above logic, it's Winter daylight, -7
    ELSE
        DATEADD ( HOUR , -7 , UTC.Field )
END

0

Bạn phải định dạng lại chuỗi cũng như chuyển đổi theo thời gian chính xác. Trong trường hợp này tôi cần thời gian của Zulu.

Declare @Date datetime;
Declare @DateString varchar(50);
set @Date = GETDATE(); 
declare @ZuluTime datetime;

Declare @DateFrom varchar (50);
Declare @DateTo varchar (50);
set @ZuluTime = DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), @Date);
set @DateString =  FORMAT(@ZuluTime, 'yyyy-MM-ddThh:mm:ssZ', 'en-US' )  
select @DateString;

0

Cách tốt nhất cho Oracle:

Với datetime mã hóa cứng:

SELECT TO_CHAR(CAST((FROM_TZ(CAST(TO_DATE('2018-10-27 21:00', 'YYYY-MM-DD HH24:MI') AS TIMESTAMP), 'UTC') AT  TIME ZONE 'EET') AS DATE), 'YYYY-MM-DD HH24:MI') UTC_TO_EET FROM DUAL

Result: 2018-10-28 00:00

Với tên cột và bảng:

SELECT TO_CHAR(CAST((FROM_TZ(CAST(COLUMN_NAME AS TIMESTAMP), 'UTC') AT  TIME ZONE 'EET') AS DATE), 'YYYY-MM-DD HH24:MI') UTC_TO_EET FROM TABLE_NAME

0

Tôi có mã để thực hiện UTC thành Địa phương và Địa phương sang UTC lần cho phép chuyển đổi bằng mã như thế này

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

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

Các chức năng có thể hỗ trợ tất cả hoặc một tập hợp các múi giờ trong IANA / TZDB do NodaTime cung cấp - xem danh sách đầy đủ tại https://nodatime.org/TimeZones

Xin lưu ý rằng trường hợp sử dụng của tôi có nghĩa là tôi chỉ cần một cửa sổ 'hiện tại', cho phép chuyển đổi thời gian trong phạm vi khoảng +/- 5 năm kể từ bây giờ. Điều này có nghĩa là phương pháp tôi đã sử dụng có thể không phù hợp với bạn nếu bạn cần một khoảng thời gian rất rộng, do cách nó tạo mã cho mỗi khoảng thời gian trong một phạm vi ngày nhất định.

Dự án nằm trên GitHub: https://github.com/elliveny/QueryServerTimeConversion

Điều này tạo mã chức năng SQL theo ví dụ này


0

Chà, nếu bạn lưu trữ dữ liệu dưới dạng ngày UTC trong cơ sở dữ liệu, bạn có thể làm điều gì đó đơn giản như

select 
 [MyUtcDate] + getdate() - getutcdate()
from [dbo].[mytable]

đây luôn là địa phương từ điểm máy chủ và bạn không dò dẫm với AT TIME ZONE 'your time zone name', nếu cơ sở dữ liệu của bạn được chuyển sang múi giờ khác như cài đặt máy khách, múi giờ được mã hóa cứng có thể cắn bạn.


-1

Đây là một cách đơn giản hơn để đưa vào tài khoản

CREATE FUNCTION [dbo].[UtcToLocal] 
(
    @p_utcDatetime DATETIME 
)
RETURNS DATETIME
AS
BEGIN
    RETURN DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), @p_utcDatetime), GETDATE())
END

6
Điều này không thực sự đưa DST vào tài khoản. Hãy thử nó : SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), '20150101'), GETDATE()). Tôi hiện đang ở CEST (UTC + 2), nhưng DST sẽ không có hiệu lực vào ngày đầu năm mới, vì vậy câu trả lời chính xác cho tôi sẽ là ngày 1 tháng 1 năm 2015 01:00. Câu trả lời của bạn, giống như câu trả lời được chấp nhận, trả về ngày 1 tháng 1 năm 2015 02:00.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.