Las conversiones de zona horaria pueden ser una tarea compleja cuando se trabaja con valores de fecha y hora en SQL Server. En este artículo, exploraremos una solución que permite realizar conversiones precisas y flexibles de zona horaria utilizando una combinación de tablas y funciones.
El problema
Cuando se trabaja con valores de fecha y hora en SQL Server, a menudo es necesario convertirlos entre diferentes zonas horarias. Esto se vuelve particularmente desafiante al considerar factores como los ajustes por el horario de verano. El objetivo es tener una solución que pueda manejar conversiones entre cualquier par de zonas horarias, teniendo en cuenta las reglas y desplazamientos específicos de cada zona.
La solución
Para resolver este problema, podemos crear dos tablas: una tabla de zonas horarias y una tabla de calendario. La tabla de zonas horarias contendrá metadatos sobre cada zona horaria, incluyendo las descripciones estándar y de horario de verano, así como los minutos de desplazamiento estándar y de horario de verano. La tabla de calendario tendrá una fila para cada año en cada zona horaria compatible, especificando las fechas de inicio y fin para los ajustes por el horario de verano.
Al poblar estas tablas con los datos necesarios, podemos crear una función que reciba un valor de fecha y hora, la zona horaria de origen y la zona horaria de destino. La función convertirá la hora de origen a UTC y luego la convertirá a la zona horaria de destino, teniendo en cuenta los ajustes por el horario de verano.
Ejemplo de código
Aquí tienes un ejemplo de cómo crear las tablas y la función necesarias:
CREATE TABLE dbo.ZonasHorarias
(
IDZonaHoraria TINYINT NOT NULL PRIMARY KEY,
DescripcionEstandar VARCHAR(64) NOT NULL UNIQUE,
DescripcionHorarioVerano VARCHAR(64) NOT NULL UNIQUE,
MinutosDesplazamientoEstandar SMALLINT NOT NULL,
MinutosDesplazamientoHorarioVerano SMALLINT NOT NULL
);
CREATE TABLE dbo.CalendarioZonasHorarias
(
[Año] DATE NOT NULL,
IDZonaHoraria TINYINT NOT NULL FOREIGN KEY
REFERENCES dbo.ZonasHorarias(IDZonaHoraria),
UTC_InicioHorarioVerano SMALLDATETIME NOT NULL,
UTC_FinHorarioVerano SMALLDATETIME NOT NULL,
Local_InicioHorarioVerano SMALLDATETIME NOT NULL,
Local_FinHorarioVerano SMALLDATETIME NOT NULL,
PRIMARY KEY ([Año], IDZonaHoraria)
);
CREATE FUNCTION dbo.ConvertirEntreZonasHorarias
(
@Origen DATETIME,
@ZonaHorariaOrigen TINYINT,
@ZonaHorariaDestino TINYINT
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT
Origen = @Origen,
src.ZonaHorariaOrigen,
[Destino] = DATEADD(MINUTE, CASE
WHEN src.UTC >= trg.UTC_InicioHorarioVerano
AND src.UTC < trg.UTC_FinHorarioVerano THEN tz.MinutosDesplazamientoHorarioVerano
ELSE tz.MinutosDesplazamientoEstandar END, src.UTC),
ZonaHorariaDestino = CASE
WHEN src.UTC >= trg.UTC_InicioHorarioVerano
AND src.UTC < trg.UTC_FinHorarioVerano THEN tz.DescripcionHorarioVerano
ELSE tz.DescripcionEstandar END
FROM
(
SELECT
src.[Año],
UTC = DATEADD(MINUTE, -CASE
WHEN @Origen >= src.Local_InicioHorarioVerano
AND @Origen < src.Local_FinHorarioVerano THEN t.MinutosDesplazamientoHorarioVerano
WHEN @Origen >= DATEADD(HOUR,-1,src.Local_InicioHorarioVerano)
AND @Origen < src.Local_InicioHorarioVerano THEN NULL
ELSE t.MinutosDesplazamientoEstandar END, @Origen),
ZonaHorariaOrigen = CASE
WHEN @Origen >= src.Local_InicioHorarioVerano
AND @Origen < src.Local_FinHorarioVerano THEN t.DescripcionHorarioVerano
ELSE t.DescripcionEstandar END
FROM dbo.CalendarioZonasHorarias AS src
INNER JOIN dbo.ZonasHorarias AS t
ON src.IDZonaHoraria = t.IDZonaHoraria
WHERE src.IDZonaHoraria = @ZonaHorariaOrigen
AND t.IDZonaHoraria = @ZonaHorariaOrigen
AND CONVERT(DATE,DATEADD(MINUTE,t.MinutosDesplazamientoEstandar,@Origen))
>= src.[Año]
AND CONVERT(DATE,DATEADD(MINUTE,t.MinutosDesplazamientoEstandar,@Origen))
< DATEADD(YEAR, 1, src.[Año])
) AS src
INNER JOIN dbo.CalendarioZonasHorarias AS trg
ON CONVERT(DATE,src.UTC) >= trg.[Año]
AND CONVERT(DATE,src.UTC) < DATEADD(YEAR, 1, trg.[Año])
INNER JOIN dbo.ZonasHorarias AS tz
ON trg.IDZonaHoraria = tz.IDZonaHoraria
WHERE trg.IDZonaHoraria = @ZonaHorariaDestino
AND tz.IDZonaHoraria = @ZonaHorariaDestino
);Una vez que se crean las tablas y la función, puedes usar la función para convertir valores de fecha y hora entre diferentes zonas horarias. Aquí tienes un ejemplo:
SELECT d.Origen, f.ZonaHorariaOrigen, f.[Destino], f.ZonaHorariaDestino
FROM @d AS d
OUTER APPLY dbo.ConvertirEntreZonasHorarias
(d.Origen, d.ZonaHorariaOrigen, d.ZonaHorariaDestino) AS f;Conclusión
Utilizando una combinación de tablas y funciones, podemos convertir con precisión y flexibilidad valores de fecha y hora entre diferentes zonas horarias en SQL Server. Esta solución tiene en cuenta los ajustes por el horario de verano y puede manejar conversiones entre cualquier par de zonas horarias. Con el ejemplo de código proporcionado, puedes implementar fácilmente esta solución en tu propio entorno de SQL Server.