Вот реализация SQL-Only, которую я недавно собрал, вы можете использовать (форумы предполагают, что CLR - единственный метод, поскольку TSQL излишне усложняется для достижения этого - не совсем afaik).Я реализовал с помощью встроенной функции, которая позволяет избежать RBAR (вы можете профилировать и проверить это для подтверждения).
Производительность отличная даже в старых школьных распределенных разделенных представлениях. Убедитесь, что ваша индексация хороша для него, даже при манипуляциях с строками на полях DateTime (чтобы обойти зависимости YearPart), я получаю желаемые запросы. Некоторые из основных разделенных таблиц имеют размер более 80 ГБ.
Конечно, вам нужно будет добавить свои временные ряды по мере необходимости и не забудьте обновить даты начала и окончания летнего времени (они могут измениться). В обоих случаях временного и дневного сбережений смещения находятся в минутах, поэтому это работает для всех сценариев, на которые я столкнулся.
Наконец, экономия Daylight офсетная всегда положительное число, обратите внимание функция обслуживает это номер эмпирического правила (весна вперед, падение назад)
If Not Exists (Select Name from sys.objects where name = 'tblTimeZones' and type = 'U')
Begin
Create Table tblTimeZones(
[ID] Int Identity (0,1) NOT NULL,
[UserID] Int NOT NULL,
[Description] NVarchar(128) NOT NULL,
[TZ_OffSet_Mins] Int NOT NULL,
[Use_DST] Bit NOT NULL,
[DST_AddOffSet] Int NOT NULL,
[DST_StartDate] DateTime NOT NULL Constraint DF_DST_StartDate Default ('1900-01-01 00:00:00.000'),
[DST_EndDate] DateTime NOT NULL Constraint DF_DST_EndDate Default ('1900-01-01 00:00:00.000'),
Constraint PK_tblTimeZones Primary Key NonClustered (ID),
Constraint UQ_tblTimeZones_Description Unique Clustered ([Description])
)
End
Go
If Exists (Select Name from sys.objects where name = 'fncV1_iCalcDateInTimeZone' and type = 'IF')
Begin
Drop Function fncV1_iCalcDateInTimeZone
End
Go
Create Function fncV1_iCalcDateInTimeZone
(
@UserID Int, @DateAndTime DateTime, @EntID Int
)
Returns Table
With SchemaBinding
As
Return (
Select TZDateAndTime =
DateAdd(
mi,
tz.TZ_OffSet_Mins +
-- Daylight Savings STARTS earlier in the Year than Ends (So, Northern Hemisphere), In Daylight Savings Time Period and Daylight Savings In Use
Case when
tz.Use_DST = 1
And SubString(Convert(Varchar(23),tz.DST_StartDate,21), 6, 18) < SubString(Convert(Varchar(23),tz.DST_EndDate,21), 6, 18)
And SubString(Convert(Varchar(23),@DateAndTime,21), 6, 18) >= SubString(Convert(Varchar(23),tz.DST_StartDate,21), 6, 18)
And SubString(Convert(Varchar(23),@DateAndTime,21), 6, 18) < SubString(Convert(Varchar(23),tz.DST_EndDate,21), 6, 18)
then tz.DST_AddOffSet
Else 0
End
+
-- Daylight Savings STARTS later in the Year than Ends (So, Southern Hemisphere), In Daylight Savings Surround Period
Case when
tz.Use_DST = 1
And SubString(Convert(Varchar(23),tz.DST_StartDate,21), 6, 18) > SubString(Convert(Varchar(23),tz.DST_EndDate,21), 6, 18)
And
(
SubString(Convert(Varchar(23),@DateAndTime,21), 6, 18) >= SubString(Convert(Varchar(23),tz.DST_StartDate,21), 6, 18)
Or
SubString(Convert(Varchar(23),@DateAndTime,21), 6, 18) < SubString(Convert(Varchar(23),tz.DST_EndDate,21), 6, 18)
)
then tz.DST_AddOffSet
Else 0
End
,@DateAndTime
)
From dbo.tblSomeEntityTable rd
Inner Join dbo.tblBranch b on rd.BranchID = b.ID
Inner Join dbo.tblUsers u on u.ID = @UserID
Inner Join dbo.tblTimeZones tz on tz.ID = case when u.UserTZOverBranchTZ = 1 then u.TimeZoneID else b.TimeZoneID End
Where
rd.ID = Case when ISNULL(@EntID, -1) = -1 then rd.ID else @EntID End
)
Go
, что двигатель и версию, пожалуйста? – gbn
Извините, я забыл упомянуть - sql 2005. – vikasde