We are writing database upgrade scripts to be run on our customers servers which could be any version of SQL Server from 2012 upwards.
One thing we are doing is migrating DATETIME
columns from local time zone format to UTC format.
I wrote a function to do this that can be called from the migration SQL.
The function uses one of 2 methods depending on the version of SQL Server - using DATETIMEOFFSET
if 2016 or newer or a fallback if older.
The issue is that older servers won't allow the function to be created as it contains the DATETIMEOFFSET
keyword.
I tried moving the DATETIMEOFFSET
SQL to a string and calling it with sp_executesql
but found out I can't call a stored procedure from a function.
Any ideas on how to handle this?
I could write 2 functions and install one or the other depending on the server version but am unsure if this is possible with SQL Server Data Tools and dacpacs.
Here is the function:
CREATE FUNCTION [dbo].[ConvertLocalDateToUtc]
(@LocalDate DATETIME2,
@LocalZone NVARCHAR(128))
RETURNS DATETIME2
AS
BEGIN
DECLARE @convertedDate DATETIME2;
IF (SELECT CAST(SERVERPROPERTY('ProductMajorVersion') AS INT)) >= 13
BEGIN
-- if SQL Server 2016 or later, this takes account of historical daylight saving times
DECLARE @ZonedLocalDate DATETIMEOFFSET = @LocalDate AT TIME ZONE @LocalZone;
DECLARE @ZonedUtcDate DATETIMEOFFSET = @ZonedLocalDate AT TIME ZONE 'UTC';
SET @convertedDate = CAST(@ZonedUtcDate AS DATETIME2);
END
ELSE
BEGIN
-- if earlier than SQL Server 2016 this uses the current time zone
-- which may or may not be the same DST as historical dates
SET @convertedDate = DATEADD(MI,(DATEDIFF(MI, SYSDATETIME(), SYSUTCDATETIME())), @LocalDate);
END
RETURN(@convertedDate);
END
We managed to fix it with the following post deployment script. It was a similar workaround to that suggested by Martin Smith in the comments. We decided to place both functions in one script rather than a base function and an upgrade to help with maintainability.
-- delete function if we already have it
IF object_id(N'ConvertLocalDateToUtc', N'FN') IS NOT NULL
DROP FUNCTION ConvertLocalDateToUtc
GO
DECLARE @SQLString nvarchar(MAX);
-- build server version specific function
-- if SQL Server 2016 or later, this takes account of historical daylight saving times
IF (SELECT CAST(SERVERPROPERTY('ProductMajorVersion') AS INT)) >= 13
BEGIN
SET @SQLString = N'
CREATE FUNCTION [dbo].[ConvertLocalDateToUtc]
(
@LocalDate DATETIME2,
@LocalZone NVARCHAR(128)
)
RETURNS DATETIME2
AS
BEGIN
DECLARE @convertedDate DATETIME2;
DECLARE @ZonedLocalDate DATETIMEOFFSET = @LocalDate AT TIME ZONE @LocalZone;
DECLARE @ZonedUtcDate DATETIMEOFFSET = @ZonedLocalDate AT TIME ZONE ''UTC'';
SET @convertedDate = CAST(@ZonedUtcDate AS DATETIME2);
RETURN(@convertedDate);
END
';
END
ELSE
BEGIN
-- if earlier than SQL Server 2016 this uses the current time zone
-- which may or may not be the same DST as historical dates
SET @SQLString = N'
CREATE FUNCTION [dbo].[ConvertLocalDateToUtc]
(
@LocalDate DATETIME2,
@LocalZone NVARCHAR(128)
)
RETURNS DATETIME2
AS
BEGIN
DECLARE @convertedDate DATETIME2;
SET @convertedDate = DATEADD(MI,(DATEDIFF(MI, SYSDATETIME(), SYSUTCDATETIME())), @LocalDate);
RETURN(@convertedDate);
END
';
END
-- run the sql to create the function
EXECUTE sp_executesql @SQLString;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.