Ecco una funzione (di nuovo agli Stati Uniti), ma è un po 'più flessibile . Converte una data UTC nell'ora locale del server. Inizia regolando la data dell'appuntamento in base all'offset corrente e quindi regola in base alla differenza dell'offset corrente e dell'offset della data dell'appuntamento.
CREATE FUNCTION [dbo].[fnGetServerTimeFromUTC]
(
@AppointmentDate AS DATETIME,
@DateTimeOffset DATETIMEOFFSET
)
RETURNS DATETIME
AS
BEGIN
--DECLARE @AppointmentDate DATETIME;
--SET @AppointmentDate = '2016-12-01 12:00:00'; SELECT @AppointmentDate;
--Get DateTimeOffset from Server
--DECLARE @DateTimeOffset; SET @DateTimeOffset = SYSDATETIMEOFFSET();
DECLARE @DateTimeOffsetStr NVARCHAR(34) = @DateTimeOffset;
--Set a standard DatePart value for Sunday (server configuration agnostic)
DECLARE @dp_Sunday INT = 7 - @@DATEFIRST + 1;
--2006 DST Start First Sunday in April (earliest is 04-01) Ends Last Sunday in October (earliest is 10-25)
--2007 DST Start Second Sunday March (earliest is 03-08) Ends First Sunday Nov (earliest is 11-01)
DECLARE @Start2006 NVARCHAR(6) = '04-01-';
DECLARE @End2006 NVARCHAR(6) = '10-25-';
DECLARE @Start2007 NVARCHAR(6) = '03-08-';
DECLARE @End2007 NVARCHAR(6) = '11-01-';
DECLARE @ServerDST SMALLINT = 0;
DECLARE @ApptDST SMALLINT = 0;
DECLARE @Start DATETIME;
DECLARE @End DATETIME;
DECLARE @CurrentMinuteOffset INT;
DECLARE @str_Year NVARCHAR(4) = LEFT(@DateTimeOffsetStr,4);
DECLARE @Year INT = CONVERT(INT, @str_Year);
SET @CurrentMinuteOffset = CONVERT(INT, SUBSTRING(@DateTimeOffsetStr,29,3)) * 60 + CONVERT(INT, SUBSTRING(@DateTimeOffsetStr,33,2)); --Hours + Minutes
--Determine DST Range for Server Offset
SET @Start = CASE
WHEN @Year <= 2006 THEN CONVERT(DATETIME, @Start2006 + @str_Year + ' 02:00:00')
ELSE CONVERT(DATETIME, @Start2007 + @str_Year + ' 02:00:00')
END;
WHILE @dp_Sunday <> DATEPART(WEEKDAY, @Start) BEGIN
SET @Start = DATEADD(DAY, 1, @Start)
END;
SET @End = CASE
WHEN @Year <= 2006 THEN CONVERT(DATETIME, @End2006 + @str_Year + ' 02:00:00')
ELSE CONVERT(DATETIME, @End2007 + @str_Year + ' 02:00:00')
END;
WHILE @dp_Sunday <> DATEPART(WEEKDAY, @End) BEGIN
SET @End = DATEADD(DAY, 1, @End)
END;
--Determine Current Offset based on Year
IF @DateTimeOffset >= @Start AND @DateTimeOffset < @End SET @ServerDST = 1;
--Determine DST status of Appointment Date
SET @Year = YEAR(@AppointmentDate);
SET @Start = CASE
WHEN @Year <= 2006 THEN CONVERT(DATETIME, @Start2006 + @str_Year + ' 02:00:00')
ELSE CONVERT(DATETIME, @Start2007 + @str_Year + ' 02:00:00')
END;
WHILE @dp_Sunday <> DATEPART(WEEKDAY, @Start) BEGIN
SET @Start = DATEADD(DAY, 1, @Start)
END;
SET @End = CASE
WHEN @Year <= 2006 THEN CONVERT(DATETIME, @End2006 + @str_Year + ' 02:00:00')
ELSE CONVERT(DATETIME, @End2007 + @str_Year + ' 02:00:00')
END;
WHILE @dp_Sunday <> DATEPART(WEEKDAY, @End) BEGIN
SET @End = DATEADD(DAY, 1, @End)
END;
--Determine Appointment Offset based on Year
IF @AppointmentDate >= @Start AND @AppointmentDate < @End SET @ApptDST = 1;
SET @AppointmentDate = DATEADD(MINUTE, @CurrentMinuteOffset + 60 * (@ApptDST - @ServerDST), @AppointmentDate)
RETURN @AppointmentDate
END
GO
grazie, andando provare questo, io farò sapere – Michel
capito come convertire UTC a altri fusi orari, AND ha tentato di implementare una funzione SqlCLR. La combinazione di loro però non ha funzionato, perché sto utilizzando l'oggetto TimeZoneInfo per calcolare le datetimes differenza, e non possono fare riferimento l'assembly che classe è in dal mio SqlProject (come sembra si può solo fare riferimento a un sottoinsieme di .NET framework) – Michel
OK - curioso del motivo per cui è necessario la classe TimeZoneInfo, data la necessità di convertire UTC in locale. Se il server SQL è configurato come essere nel tuo avvenire fuso orario locale (accordo - questo è un vincolo), allora il vostro c funzione # diventa qualcosa come 'return new SqlDateTime (utcDate.Value.toLocalTime());' . Non è necessario specificare un fuso orario. Ho capito male? –