SQL Server Agent y el cambio de hora
Hace algunos días nos hemos enfrentado al cambio de hora. ¿Cómo lo habéis llevado? ¿Habéis tenido algún problema? Si tenéis todo con UTCs imagino que no, pero si tenéis fechas locales seguro que os habéis encontrado alguna que otra sorpresa.
Hasta que empecé a trabajar, me encantaba este cambio de hora. ¡Una hora más en el fin de semana! Para descansar más, ir de fiesta,… lo que quieras. Pero como técnica … éste es “el malo”, es el que más problemas me da porque he heredado un sistema basado en horas locales. Y es que tengo dos momentos distintos con la misma hora y no puedo distinguirlos: las 2 am.
Uno de los primeros consejos que recibiréis por mi parte, basada en la mala experiencia (esa que se graba en tu mente a fuego) es que a la hora de modelar “siempre hacer todo con horas UTCs” . Así te evitarás los problemas de los cambios de hora. De verdad, aunque no creas que lo vayas a necesitar porque se trate de un negocio local, usa UTCs en tus tablas. Te evitarás muchos problemas.
Veamos un ejemplo.
Registro creado a las 2:30 am local – 0:30 UTC
Registro creado a las 2:10 am local – 1:10 UTC
Si miras las horas locales ¿Cuál se creó antes? No puedes decirlo. Si miras las UTCs, en cambio, sí.
Pero este no es un problema sólo de la creación de los registros. El SQL Agent funciona con la hora del servidor, por lo tanto hora local. Entonces ¿Cómo hago para que se lancen los jobs según la hora UTC? Supongamos, por ejemplo, que necesito lanzar unos procesos a partir de las 0h UTCs y como tardan mucho quiero ajustar y que se lancen cuanto antes. ¿Cómo lo haríamos?
Para lograrlo necesitaré que cada job que quiera esto tenga dos programaciones, una para cuando esté el horario de invierno (que llamaremos Winter) y otra para la del verano (que llamaremos Summer).
Luego además programaré a las 0h un job, al que he llamado “WinterSummerSchedulerSwitch”, cuya función es detectar si estamos en horario de invierno o de verano y activar el scheduler correspondiente.
Aquí os dejo el código que sería para un servidor ubicado en España.
USE [msdb]
GO
DECLARE @numh smallint
Select @numh = datediff(HOUR,getutcdate(),getdate())
declare @summer table (schedule_id int)
declare @winter table (schedule_id int)
declare @id int
IF @numh = 1
BEGIN
-- Para HORARIO DE INVIERNO
insert into @Summer (schedule_id)
SELECT schedule_id
FROM sysschedules_localserver_view
where [name]='Summer'
While EXISTS (select top 1 1 from @Summer)
BEGIN
SELECT @id = schedule_id from @Summer
EXEC dbo.sp_update_schedule
@schedule_id = @id,
@enabled = 0
DELETE FROM @Summer where schedule_id = @id
END
insert into @Winter (schedule_id)
SELECT schedule_id
FROM sysschedules_localserver_view
where [name]='Winter'
While EXISTS (select top 1 1 from @Winter)
BEGIN
SELECT @id = schedule_id from @Winter
EXEC dbo.sp_update_schedule
@schedule_id = @id,
@enabled = 1
DELETE FROM @Winter where schedule_id = @id
END
END
ELSE
BEGIN
-- Para HORARIO DE VERANO
insert into @Summer (schedule_id)
SELECT schedule_id
FROM sysschedules_localserver_view
where [name]='Summer'
While EXISTS (select top 1 1 from @Summer)
BEGIN
SELECT @id = schedule_id from @Summer
EXEC dbo.sp_update_schedule
@schedule_id = @id,
@enabled = 1
DELETE FROM @Summer where schedule_id = @id
END
insert into @Winter (schedule_id)
SELECT schedule_id
FROM sysschedules_localserver_view
where [name]='Winter'
While EXISTS (select top 1 1 from @Winter)
BEGIN
SELECT @id = schedule_id from @Winter
EXEC dbo.sp_update_schedule
@schedule_id = @id,
@enabled = 0
DELETE FROM @Winter where schedule_id = @id
END
END
Yo lo he probado en este cambio horario, y me ha evitado cambiar las programaciones de los jobs, asi que he decidido compartirlo con vosotros. ¿ Alguno se ha encontrado también con esta necesidad? ¿Cómo lo ha solucionado? Me encantaría que lo compartierais en los comentarios.