Я создал две функции SQL, чтобы конвертировать даты Dynamic AX UTC в соответствующую дату/время в часовом поясе из таблицы TIMEZONESRULESDATA. Они, похоже, работают в сценариях, которые я тестировал, но я был бы рад получить обратную связь.
Первая функция подается в формате UTC DateTime и TZID из любой таблицы AX и генерирует дату/время в часовом поясе с какими-либо регулировками летнее:
-- *** IMPORTANT NOTE: @@DATEFIRST must be 7 for this to work ***
CREATE FUNCTION [dbo].[ConvertUTCDateTime] (@DateTime DATETIME, @TZID INT)
RETURNS DATETIME
AS
BEGIN
DECLARE @AdjustedDateTime DATETIME
SET @[email protected]
-- Fields to be extracted from TIMEZONESRULESDATA record for TZID
DECLARE @Bias INT, @DBias INT
DECLARE @DMonth INT, @DDayOfWeek INT, @DDay INT, @DHour INT, @DMinute INT, @DSecond INT -- Start of Daylight Saving
DECLARE @SMonth INT, @SDayOfWeek INT, @SDay INT, @SHour INT, @SMinute INT, @SSecond INT -- End of Daylight Saving
-- Daylight Saving Date/Time ranges
DECLARE @DSTFromDateTime1 DATETIME, @DSTToDateTime1 DATETIME, @DSTFromDateTime2 DATETIME, @DSTToDateTime2 DATETIME
SELECT
@Bias=tzr.BIAS,@DBias=tzr.DBIAS,
@DMonth=tzr.DMONTH, @DDayOfWeek=tzr.DDAYOFWEEK, @DDay=tzr.DDAY, @DHour=tzr.DHOUR, @DMinute=tzr.DMINUTE, @DSecond=tzr.DSECOND,
@SMonth=tzr.SMONTH, @SDayOfWeek=tzr.SDAYOFWEEK, @SDay=tzr.SDAY, @SHour=tzr.SHOUR, @SMinute=tzr.SMINUTE, @SSecond=tzr.SSECOND
FROM MyAXDatabase..TIMEZONESRULESDATA tzr
WHERE [email protected]
IF @Bias IS NOT NULL
BEGIN
SET @AdjustedDateTime=DATEADD(MINUTE, (-1)*@Bias, @DateTime) -- Standard Time Zone Adjustment from UTC
IF @DMonth>0 -- If there is Daylight Saving
BEGIN
SET @DSTFromDateTime1=dbo.GetDSTDateTime(@AdjustedDateTime, @DMonth, @DDayOfWeek, @DDay, @DHour, @DMinute, @DSecond) -- Get DS Start date in year
SET @DSTToDateTime2=dbo.GetDSTDateTime(@AdjustedDateTime, @SMonth, @SDayOfWeek, @SDay, @SHour, @SMinute, @SSecond) -- Get DS End date in year
IF @DSTFromDateTime1>@DSTToDateTime2
BEGIN
SET @DSTToDateTime1= DATEADD(SECOND, -1, CAST(DATEFROMPARTS(YEAR(@AdjustedDateTime)+1, 1, 1) as DATETIME)) -- End of Current Year
SET @DSTFromDateTime2= DATEFROMPARTS(YEAR(@AdjustedDateTime), 1, 1) -- Start of Current Year
END
ELSE
BEGIN
SET @[email protected]
SET @[email protected]
END
IF @AdjustedDateTime BETWEEN @DSTFromDateTime1 AND @DSTToDateTime1
OR @AdjustedDateTime BETWEEN @DSTFromDateTime2 AND @DSTToDateTime2
SET @AdjustedDateTime=DATEADD(MINUTE, (-1)*@DBias, @AdjustedDateTime) -- Make Daylight Saving adjustment if in DST date range
END
END
RETURN @AdjustedDateTime
END
Вторая функция работает в летних начать или дату окончания на основе параметров, поданных с полей TIMEZONESRULESDATA:
-- *** IMPORTANT NOTE: @@DATEFIRST must be 7 for this to work ***
CREATE FUNCTION [dbo].[GetDSTDateTime](
@DateTime DATETIME, -- Base Date
@Month INT, -- Month for Start/End of DST
@DayOfWeek INT, -- Day of Week 0=Sun..6=Sat (based on coding in TIMEZONESRULESDATA table)
@Day INT, -- Week of the Month (confusing?!) 1-5 ; 5 means last week
@Hour INT,
@Minute INT,
@Second INT
) RETURNS DATETIME
AS
BEGIN
DECLARE @MyDateTime DATETIME
SET @MyDateTime=DATEFROMPARTS(YEAR(@DateTime), @Month, 1) -- First day of DST Start/End Month from @BaseDate year
SET @[email protected] + 1 -- Adjust to tie in with SQL DoW 1-7
-- Establish first selected DayOfWeek in the month
IF @DayOfWeek >= DATEPART(WEEKDAY, @MyDateTime)
SET @MyDateTime=DATEADD(DAY, @DayOfWeek - DATEPART(WEEKDAY, @MyDateTime), @MyDateTime)
ELSE
SET @MyDateTime=DATEADD(DAY, 7-(DATEPART(WEEKDAY, @MyDateTime) - @DayOfWeek), @MyDateTime)
-- Add the appropriate number of weeks
SET @MyDateTime=DATEADD(DAY, 7*(@Day-1), @MyDateTime)
-- For last week of month ensure that date is in correct month
WHILE MONTH(@MyDateTime)<>@Month
BEGIN
SET @MyDateTime=DATEADD(DAY, -7, @MyDateTime)
END;
-- Add on Hours, Minutes and Seconds
SET @MyDateTime=DATEADD(SECOND, @Second, DATEADD(MINUTE, @Minute, DATEADD(HOUR, @Hour, @MyDateTime)))
RETURN @MyDateTime
END
Нам не хватало 5 = на прошлой неделе - спасибо! Правильно ли я полагаю, что если запись действительна только в течение определенного года, SDAY будет точным днем месяца? Кроме того, что значит иметь не-0 запись за год? Являются ли настройки действительными только для этого года или с того года? Мы намерены использовать данные, чтобы написать собственный локальный часовой пояс/DST для преобразования UTC SQL (в этом случае мы не можем использовать X ++). Идея состоит в том, чтобы использовать тип данных datetimeoffset SQL Server для хранения данных. – BuschnicK
Я не знаю о точном значении года. AX подготовлен для импорта правил часового пояса, поэтому я предполагаю, что это будет конкретный год. Тестирование покажет. Удачи вам в преобразовании местного времени, но мое первоначальное ощущение заключается в том, что вы на неправильном пути. –
«неправильный трек» - моя кишка соглашается с вами. Однако, что вы предлагаете? Мы можем использовать только SQL, и мы должны конвертировать произвольные даты (прошлое, настоящее, будущее) из произвольного часового пояса в UTC. – BuschnicK