简体   繁体   English

T-SQL:四舍五入到最近的 15 分钟间隔

[英]T-SQL: Round to nearest 15 minute interval

What's the best way to round an HH:MM value to the closest 15 minute interval?将 HH:MM 值舍入到最接近的 15 分钟间隔的最佳方法是什么? I don't track seconds so they don't matter.我不跟踪秒,所以它们无关紧要。

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

I am currently using a dateadd \/ datediff variant with a zero (0) date for this.我目前正在为此使用带有零 (0) 日期的 dateadd \/ datediff 变体。 No Casting required:无需铸造:

select dateadd(minute, datediff(minute,0,GETDATE()) / 15 * 15, 0)

I know this is a old post but wanted to share my answer.我知道这是一篇旧帖子,但想分享我的答案。 This builds on @hbrowser response.这建立在@hbrowser 响应之上。 Here is what I've come up with.这是我想出的。 This will round up or down to the nearest 15 minutes.这将向上或向下舍入到最接近的 15 分钟。

SELECT DATEADD(MINUTE, ROUND(DATEDIFF(MINUTE, 0, GETDATE()) / 15.0, 0) * 15, 0);

By doing this logic inline, rather than inside a user defined function, over large recordsets you should experience greater performance.通过在大型记录集上执行此逻辑内联而不是在用户定义的函数中,您应该体验到更高的性能。

You can change the way rounding occurs by swapping the ROUND function to use FLOOR or CAST expr AS INT to always round down or use CEILING to always round up.您可以通过将ROUND函数交换为使用FLOORCAST expr AS INT始终向下舍入或使用CEILING始终向上舍入来更改舍入的方式。

Your individual use case will determine what style of rounding you may need to use.您的个人用例将决定您可能需要使用哪种类型的舍入。

The following script can be used to observe the differences offered by the different rounding techniques:以下脚本可用于观察不同舍入技术提供的差异:

NOTE: to simplify the output each result has been casted to TIME(0), this is only done to simplify the output for this particular example.注意:为了简化输出,每个结果都被转换为 TIME(0),这样做只是为了简化这个特定示例的输出。

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

This was answered here How to Round a Time in T-SQL and i think it should work for you to.这在How to Round a Time in T-SQL 中得到了回答,我认为它应该对你有用。

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)

You can round a date to the nearest quarter like:您可以将日期四舍五入到最近的四分之一,例如:

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

Casting datetime to double precesion to avoid overflows, double = float(53).将日期时间转换为双精度以避免溢出,double = float(53)。 Multiply by 24*4, the number of quarters in a day.乘以 24*4,即一天的季度数。 Round to the nearest multiple of quarters with floor(), and then divide by 24*4 to convert back to normal time.使用 floor() 四舍五入到最接近的四分位数倍数,然后除以 24*4 以转换回正常时间。

Tried Andomar's answer and there was rounding issues at 30 and 00 - so a few tweaks and this works perfectly:尝试了 Andomar 的答案,在 30 和 00 处存在舍入问题 - 所以进行了一些调整,这非常有效:

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

Okay easiest way:好的最简单的方法:

convert the minutes to a decimal number by dividing by 60.通过除以 60 将分钟转换为十进制数。

8/60 = 0.1333333333333333

multiply by 4乘以 4

0.1333333333333333 * 4   = 0.5333333333333333

Round the product:圆形产品:

Round(0.5333333333333333,0) = 1

divide the round number by 4将整数除以 4

1/4 = 0.25 = 15 minutes

if you want the minutes just multiply it by 60如果你想要分钟只需乘以 60

0.25*60 = 15

Give a man a fish....给男人一条鱼....

DECLARE @t time  ='00:51:00.000' 
DECLARE @m  int = DATEPART(MI,@t)%15

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

-- 2012
SELECT DATEADD(mi,IIF(@m >=8,15-@m,-1*@m),@t)

Try this:试试这个:

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))

--This is my favorite way to round time ——这是我最喜欢的打发时间的方式

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)

how about this one?这个怎么样? (variable added for readability) (为可读性添加了变量)

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

This will round to the nearest 15 minutes.这将四舍五入到最接近的 15 分钟。 You can modify @ROUND to the interval of your choice.您可以将@ROUND 修改为您选择的间隔。

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

Premise breaks down to figuring out what increment you want, what's that as a percent of 60 minutes...then figure out the needed number of increments to get there...take the INT value (this chops off remainders) and there you have it, a simple function to round Up or down to the closest increment.前提分解为弄清楚你想要什么增量,60分钟的百分比是多少......然后计算出到达那里所需的增量数量......取INT值(这会去掉余数),你就有了它是一个简单的函数,可以向上或向下舍入到最接近的增量。

Simple function:简单功能:

    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
    DECLARE   @Date             DATETIME = GETDATE()

    SELECT    @Date
            , DATEADD(ms, 900000 - DATEDIFF(ms, CAST(@Date AS DATE), @Date) % 900000, @Date)

To set block in 15 minutes:在 15 分钟内设置块:

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
create function RoundQuarterHour
(
    @dt datetime
)
returns datetime
as
begin
    declare @result datetime
    declare @mm int
    set @mm=datepart(minute,@dt)
    set @result = dateadd(minute,-@mm + (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'

Time rounding in T-SQL is actually very problematic and many times inaccurate. T-SQL 中的时间舍入实际上是非常有问题的,而且很多时候是不准确的。

Years ago, I moved all rounding of times into code vs. using all the extra hub-bub one has to do in T-SQL to make it happen and to happen accurately.多年前,我将所有时间都转移到了代码中,而不是使用 T-SQL 中必须做的所有额外的 hub-bub 来实现它并准确地实现它。 Rounding times in code is easier and much more accurate.代码中的舍入时间更容易也更准确。

If you're stuck in T-SQL and have no supporting code, or don't have access to that code, then follow the examples previously mentioned.如果您被困在 T-SQL 中并且没有支持代码,或者无法访问该代码,请按照前面提到的示例进行操作。 Otherwise, I humbly recommend letting code do the work.否则,我谦虚地建议让代码完成这项工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM