2009-05-06 81 views
35

¿Cuál es la mejor manera de redondear un valor de HH: MM al intervalo de 15 minutos más cercano? No sigo los segundos para que no importen.T-SQL: redondeado al intervalo de 15 minutos más cercano

00:08:00 becomes 00:15:00 
00:07:00 becomes 00:00:00 
01:59:00 becomes 02:00:00 

y así sucesivamente. ¿Existe un método de declaración elegante, sin UDF o Case para hacer esto?

EDIT: Aquí está el SQL que estoy usando para obtener los valores anteriores que me gustaría para redondear:

CONVERT(CHAR(8), DATEADD(n, SUM(DATEDIFF(n, starttime, stoptime)), 0), 108) 

starttime y stoptime son SQL datetime s.

+0

¿Qué tipo de datos tiene usted el valor almacenado como? – Tomalak

+0

Eche un vistazo a http://stackoverflow.com/questions/829825/how-to-reformat-datetime-in-sql-with-ceiling-or-flooring-method/829927#829927 – ahains

+1

@Tomalak - Es un SUMA de fechas de tiempo DATEDIFF convertidas a HH: MM: SS. Lo he estado reconstruyendo a partir de basura que encontré en línea. Actualizaré la pregunta con mi SQL – Dzejms

Respuesta

25

Esto fue respondido aquí How to Round a Time in 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) 
+1

Lo vi y pensé que era excesivo. Solo pensé que debería haber un enfoque más simple cuando no me importan las horas o los segundos. Solo quiero tomar un número entre 0 y 60, y redondearlo apropiadamente a un cuarto de hora.Voy a echar otro vistazo a la respuesta anterior. – Dzejms

+0

Bueno, no es exactamente lo que estaba buscando, pero al menos ahora tengo una UDF flexible que resuelve este problema y las futuras potentialy. – Dzejms

5

Puede redondear una fecha cercana al barrio como:

cast(floor(cast(getdate() as float(53))*24*4)/(24*4) as datetime) 

casting de fecha y hora para duplicar la precesión para evitar desbordamientos, doble = flotador (53). Multiplique por 24 * 4, la cantidad de cuartos en un día. Redondea al múltiplo de cuartos más cercano con piso(), y luego divídelo entre 24 * 4 para convertirlo a tiempo normal.

+4

Sólo para que quede claro, esto no redondea al cuarto más cercano. El piso() siempre lo convierte en el último trimestre que acaba de ocurrir. Con el fin de conseguir el cuarto más cercano, que tendría que sustituir que con la función round() con una precisión de 0. –

0
create function RoundQuarterHour 
(
    @dt datetime 
) 
returns datetime 
as 
begin 
    declare @result datetime 
    declare @mm int 
    set @mm=datepart(minute,@dt) 
    set @result = dateadd(minute,[email protected] + (round(@mm/cast(15 as float),0)*15) , @dt) 

    return @result 
end 
go 


      select dbo.RoundQuarterHour('2009-may-5 20:00') , '00' 
union all select dbo.RoundQuarterHour('2009-may-5 20:01') , '01' 
union all select dbo.RoundQuarterHour('2009-may-5 20:07') , '07' 
union all select dbo.RoundQuarterHour('2009-may-5 20:08') , '08' 
union all select dbo.RoundQuarterHour('2009-may-5 20:22') , '22' 
union all select dbo.RoundQuarterHour('2009-may-5 20:23') , '23' 
union all select dbo.RoundQuarterHour('2009-may-5 20:37') , '37' 
union all select dbo.RoundQuarterHour('2009-may-5 20:38') , '38' 
union all select dbo.RoundQuarterHour('2009-may-5 20:52') , '52' 
union all select dbo.RoundQuarterHour('2009-may-5 20:53') , '53' 
union all select dbo.RoundQuarterHour('2009-may-5 20:59') , '59' 
0

El redondeo de tiempo en T-SQL es realmente muy problemático y muchas veces inexacto.

Hace años, moví todo el redondeo de tiempos en el código frente al uso de todo el cubo-bub adicional que uno tiene que hacer en T-SQL para que ocurra y ocurra con precisión. Redondear los tiempos en el código es más fácil y mucho más preciso.

Si está atrapado en T-SQL y no tiene un código de soporte, o no tiene acceso a ese código, siga los ejemplos mencionados anteriormente. De lo contrario, humildemente recomiendo dejar que el código haga el trabajo.

4

Probamos la respuesta de Andomar y no redondeaba los problemas a los 30 y 00 - por lo que un par de retoques y esto funciona a la perfección:

cast(round(floor(cast(getdate() as float(53))*24*4)/(24*4),5) as smalldatetime) 

Esto mostrará el último aumento de 15 minutos, no es el más cercano, es decir, que ganó' Seguir adelante, que es exactamente lo que necesitaba.

+0

Exactamente el fragmento de código que necesitaba –

55

Actualmente estoy usando una variante dateadd/datediff 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 es.

Esto funcionará para las fechas al menos hasta el año 5500 antes de los fails datediff debido a un desbordamiento. Sin embargo, si intenta usar una segunda precisión, lo anterior fallará de inmediato.

El uso de otra fecha fija, como '2009-01-01', o la fecha de hoy (advertencia, SQL más feo) lo arreglará. Una fecha futura también funcionará. Siempre que tenga una parte de tiempo de 00:00:00, puede basar otra fecha y hora en ella.

por ejemplo: redondo con una precisión de 30 segundos:

select dateadd(second, round(datediff(second, '2010-01-01', GETDATE())/30.0, 0) * 30, '2010-01-01'); 
+1

Will esta ronda con interés el próximo punto del minuto 15? –

+4

Esta es una buena solución, mejor que el aceptado (complejidad- y velocidad- wise) –

+4

El método de arriba funciona bien, pero trunca, en lugar de redondeo, por ejemplo, seleccione dateadd (minutos, datediff (minutos, 0, '2015-05-22T17: 29: 00')/15 * 15, 0) devuelve 22/05/2015 17: 15: 00.000 –

0

¿qué tal éste? (Variable añadida para facilitar la lectura)

create function dbo.FloorTimeToQuarters 
(
@dt as datetime 
) 
RETURNS datetime 
as 

BEGIN 

DECLARE @timeAsInt bigint 
SET @timeAsInt = (cast(@dt as float) * 96) 
RETURN DateAdd(hour, @timeAsInt % 96, cast(@timeAsInt/96 as datetime) ) 

END 
1

Prueba esto:

Declare @Dt DateTime 
Set @Dt = getDate() 

Select DateAdd(minute, 
     15 * ((60 * Datepart(hour, @Dt) + 
     Datepart(Minute, @Dt)+ 
     Case When DatePart(second, @Dt) < 30 
     Then 7 Else 8 End)/15), 
    DateAdd(day, DateDiff(day, 0, @Dt), 0)) 
0

Para establecer el bloque de 15 minutos:

CREATE FUNCTION RoundQuarterHour (
    @dt DATETIME 
) RETURNS DATETIME 

AS 
BEGIN 
    DECLARE @date DATETIME 
    SET @date = CONVERT(varchar(16),@dt,121) --Sin segundos, ni milisegundos 
    RETURN DATEADD(MINUTE,(DATEPART(MINUTE,@date) % 15)*-1, @date) 
END 

PRINT dbo.RoundQuarterHour('2011/01/01 18:00:07') --Jan 1 2011 6:00PM 
PRINT dbo.RoundQuarterHour('2011/01/01 18:01:07') --Jan 1 2011 6:00PM 
PRINT dbo.RoundQuarterHour('2011/01/01 18:13:07') --Jan 1 2011 6:00PM 
PRINT dbo.RoundQuarterHour('2011/01/01 18:14:07') --Jan 1 2011 6:00PM 
PRINT dbo.RoundQuarterHour('2011/01/01 18:15:07') --Jan 1 2011 6:15PM 
PRINT dbo.RoundQuarterHour('2011/01/01 18:16:07') --Jan 1 2011 6:15PM 
1
DECLARE @t time ='00:51:00.000' 
DECLARE @m int = DATEPART(MI,@t)%15 

-- 2008 
SELECT DATEADD(mi,CASE WHEN @m >=8 THEN [email protected] ELSE -1*@m END,@t) 

-- 2012 
SELECT DATEADD(mi,IIF(@m >=8,[email protected],-1*@m),@t) 
1

Bien forma más fácil:

convertir el minutos a un número decimal por dividir g por 60.

8/60 = 0.1333333333333333 

multiplicar por 4

0.1333333333333333 * 4 = 0.5333333333333333 

Ronda del producto:

Round(0.5333333333333333,0) = 1 

división del número redondo de 4

1/4 = 0.25 = 15 minutes 

si desea que los minutos simplemente multiplíquelo por 60

0.25*60 = 15 

Dale a un hombre un pez ....

+0

he estado usando este método desde hace años, funciona perfectamente para mí ... –

0

--Este es mi forma favorita de tiempo de ida

DECLARE @Time DATETIME = GETDATE() 
     ,@RoundInterval INT = 30 --in minutes, needs to be a number that can be divided evenly into 60 
     ,@RoundDirection INT = 2 --0 is down to the last interval, 1 is to the nearest interval, 2 is up to the next interval 

SELECT DATEADD(MINUTE,DATEDIFF(MINUTE,0,DATEADD(SECOND,30*@RoundDirection*@RoundInterval,@Time))/@RoundInterval*@RoundInterval,0) 
0

esta ronda a los 15 minutos más cercanos. Puede modificar @ROUND al intervalo de su elección.

Declare @Dt DateTime = '2016-01-01 14:38:00' 
DECLARE @ROUND int = 15; 
SELECT 
CASE WHEN (DATEPART(MINUTE, @Dt) % @ROUND) * 60 + DATEPART(SECOND, @Dt) < (30 * @ROUND) 
THEN DATEADD(minute, datediff(minute,0, @Dt)/@ROUND * @ROUND, 0) 
ELSE DATEADD(minute, (DATEDIFF(minute,0, @Dt)/@ROUND * @ROUND) + @ROUND, 0) 
END 
11

Sé que es una publicación anterior, pero quería compartir mi respuesta. Esto se basa en la respuesta @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); 
+0

creo que debe constar expresamente en su respuesta lo que lo hace desde _distinto_ [@ de hbrowser] (http: // stackoverflow. com/a/1624984/241211) (es decir el suyo utiliza 'ROUND', mientras que su/ella hace un implícito' FLOOR' con división entera). – Michael

0

Premisa se descompone para averiguar lo de la subasta que desea, ¿qué es eso como un porcentaje de 60 minutos ... a continuación, averiguar el número necesario de incrementos para llegar allí ... toma el valor INT (esta chuletas de los residuos) y ahí lo tienes, una función simple para redondear hacia arriba o hacia abajo al incremento más cercano.

función simple:

ALTER FUNCTION [dbo].[RoundOffDateTime] 
(
    @IncDate DATETIME, 
    @Increment INT 
) 
RETURNS SMALLDATETIME 
AS 
BEGIN 

    DECLARE @IncrementPercent DECIMAL(2,2) = CAST(@Increment as decimal)/60 
    DECLARE @IncMinutes REAL = ROUND(CAST(DATEPART(mi,@IncDate) as decimal)/CAST(@Increment as decimal),0) 
    DECLARE @MinutesNeeded INT = CAST(@IncMinutes * @Increment as INT) 

    RETURN CAST(DATEADD(mi,@MinutesNeeded,DATEADD(ss,-DATEPART(ss,@IncDate),DATEADD(mi,-DATEPART(mi,@IncDate),@IncDate))) as smalldatetime) 

END 
Cuestiones relacionadas