J'ai créé deux fonctions SQL pour convertir les dates Dynamics AX UTC en date/heure de fuseau horaire approprié à partir de la table TIMEZONESRULESDATA. Ils semblent travailler dans les scénarios que j'ai testés, mais je serais ravi de recevoir des commentaires.
La première fonction est amenée DateTime UTC et TZID de toute table de AX et génère la date/heure dans le fuseau horaire avec un réglage de l'heure d'été:
-- *** 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
La deuxième fonction est les économies diurnes commencent ou date de fin basée sur les paramètres alimentés par les champs 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
Il nous manquait la partie 5 = dernière semaine - merci! Ai-je raison de supposer que si une entrée n'est valable que pour une année spécifique, le SDAY sera le jour exact du mois? Aussi, qu'est-ce que cela signifie d'avoir une entrée non-0 pour l'année? Les paramètres sont-ils valables uniquement pour cette année ou à partir de cette année? Nous avons l'intention d'utiliser les données pour écrire notre propre SQL local time-time/DST en conversion UTC (nous ne pouvons pas utiliser X ++ dans ce cas). L'idée consiste à utiliser le datatype datetimeoffset de SQL Server pour stocker les dates-heures. – BuschnicK
Je ne connais pas le sens exact de l'année. AX est préparé pour l'importation des règles de fuseau horaire, donc mon estimation serait l'année spécifique seulement. Les tests montreront. Bonne chance avec votre conversion en heure locale, mais mon sentiment initial est que vous êtes sur une mauvaise piste. –
"mauvaise piste" - mon instinct est d'accord avec vous. Cependant, que proposez-vous? Nous ne pouvons utiliser que SQL et nous devons convertir des dates arbitraires (passées, présentes, futures) d'un fuseau horaire arbitraire en UTC. – BuschnicK