Si encuentras algún fallo en tu código o proyecto, recuerda probar siempre en un ambiente de testing antes añadir el código al trabajo final.
Solución:
Actualmente estoy usando una variante dateadd/dateiff con una fecha cero (0) para esto. No se requiere fundición:
select dateadd(minute, datediff(minute,0,GETDATE()) / 15 * 15, 0)
GETDATE() es cualquiera que sea su fecha y hora.
Esto funcionará para fechas al menos hasta el año 5500 antes de que el archivo dateiff falle debido a un desbordamiento. Sin embargo, si intenta usar la segunda precisión, la anterior fallará de inmediato.
El uso de otra fecha fija, como ‘2009-01-01’, o la fecha de hoy (advertencia, SQL más feo) solucionará eso. Una fecha futura también funcionará. Siempre que tenga una parte de tiempo de 00:00:00, puede basar otra fecha y hora en él.
por ejemplo: redondear a los 30 segundos más cercanos:
select dateadd(second, round(datediff(second, '2010-01-01', GETDATE()) / 30.0, 0) * 30, '2010-01-01');
Sé que esta es una publicación antigua, pero quería compartir mi respuesta. Esto se basa en la respuesta de @hbrowser. Esto es lo que se me ocurrió. Esto redondeará hacia arriba o hacia abajo a los 15 minutos más cercanos.
SELECT DATEADD(MINUTE, ROUND(DATEDIFF(MINUTE, 0, GETDATE()) / 15.0, 0) * 15, 0);
Al hacer esta lógica en línea, en lugar de dentro de una función definida por el usuario, en grandes conjuntos de registros debería experimentar un mayor rendimiento.
Puede cambiar la forma en que se produce el redondeo intercambiando el
ROUND
función a utilizarFLOOR
oCAST expr AS INT
redondear hacia abajo o usar siempreCEILING
para redondear siempre.
Su caso de uso individual determinará qué estilo de redondeo puede necesitar usar.
El siguiente script se puede utilizar para observar las diferencias que ofrecen las distintas técnicas de redondeo:
NOTA: para simplificar la salida, cada resultado se ha convertido a TIME(0), esto solo se hace para simplificar la salida de este ejemplo en particular.
DECLARE @SequenceStart SmallDateTime = CAST(GETDATE() AS Date);
DECLARE @SequenceEnd SmallDateTime = DateAdd(HOUR, 2, @SequenceStart); -- Recursive CTEs should always have an upper limit
DECLARE @SequenceIntMins INT = 5; -- increment by 5 to show the difference with rounding
WITH TimeSequence([Time]) as
(
SELECT @SequenceStart as [Time]
UNION ALL
SELECT DateAdd(MINUTE, 5, [Time]) FROM TimeSequence
WHERE [Time] <= @SequenceEnd
)
SELECT [Time] = Cast([Time] as TIME(0))
, Rounded = CAST(DATEADD(MINUTE, ROUND(DATEDIFF(MINUTE, 0, [Time]) / 15.0, 0) * 15, 0) as TIME(0))
, Casted = CAST(DATEADD(MINUTE, CAST(DATEDIFF(MINUTE, 0, [Time]) / 15.0 AS INT) * 15, 0) as TIME(0))
, Floored = CAST(DATEADD(MINUTE, FLOOR(DATEDIFF(MINUTE, 0, [Time]) / 15.0) * 15, 0) as TIME(0))
, Ceilinged = CAST(DATEADD(MINUTE, CEILING(DATEDIFF(MINUTE, 0, [Time]) / 15.0) * 15, 0) as TIME(0))
FROM TimeSequence OPTION ( MaxRecursion 1000);
-- MaxRecursion may be neccessary if you change the interval or end of the sequence
Time Rounded Casted Floored Ceilinged 00:00:00 00:00:00 00:00:00 00:00:00 00:00:00 00:05:00 00:00:00 00:00:00 00:00:00 00:15:00 00:10:00 00:15:00 00:00:00 00:00:00 00:15:00 00:15:00 00:15:00 00:15:00 00:15:00 00:15:00 00:20:00 00:15:00 00:15:00 00:15:00 00:30:00 00:25:00 00:30:00 00:15:00 00:15:00 00:30:00 00:30:00 00:30:00 00:30:00 00:30:00 00:30:00 00:35:00 00:30:00 00:30:00 00:30:00 00:45:00 00:40:00 00:45:00 00:30:00 00:30:00 00:45:00 00:45:00 00:45:00 00:45:00 00:45:00 00:45:00 00:50:00 00:45:00 00:45:00 00:45:00 01:00:00 00:55:00 01:00:00 00:45:00 00:45:00 01:00:00 01:00:00 01:00:00 01:00:00 01:00:00 01:00:00 01:05:00 01:00:00 01:00:00 01:00:00 01:15:00
Esto fue respondido aquí Cómo redondear una hora en T-SQL y creo que debería funcionar para usted.
CREATE FUNCTION [dbo].[RoundTime] (@Time datetime, @RoundTo float) RETURNS datetime
AS
BEGIN
DECLARE @RoundedTime smalldatetime, @Multiplier float
SET @Multiplier = 24.0 / @RoundTo
SET @RoundedTime= ROUND(CAST(CAST(CONVERT(varchar, @Time, 121) AS datetime) AS float) * @Multiplier, 0) / @Multiplier
RETURN @RoundedTime
END
-- Usage
SELECT dbo.RoundTime('13:15', 0.5)