将HH:MM值舍入到最接近的15分钟间隔的最佳方法是什么?我不追踪秒,所以它们无所谓。
00:08:00 becomes 00:15:00
00:07:00 becomes 00:00:00
01:59:00 becomes 02:00:00
等等。这样做是否有优雅的非UDF或Case语句方法?
编辑:以下是我用来获取上述值的SQL:
CONVERT(CHAR(8), DATEADD(n, SUM(DATEDIFF(n, starttime, stoptime)), 0), 108)
starttime
和stoptime
是SQL datetime
s。
答案 0 :(得分:63)
我目前正在使用dateadd / datediff变体,其日期为零(0)。不需要施法:
select dateadd(minute, datediff(minute,0,GETDATE()) / 15 * 15, 0)
GETDATE()是你的约会时间。
这将适用于日期至少5500年之前的日期,因为日期已经过期。但是,如果您尝试使用第二个精度,则上面会立即失败。
使用另一个固定日期,如'2009-01-01',或今天的日期(警告,更丑陋的SQL)将解决这个问题。未来的日期也将有效。只要它的时间部分为00:00:00,您就可以在其上建立另一个日期时间。
例如:舍入到最接近的30秒:
select dateadd(second, round(datediff(second, '2010-01-01', GETDATE()) / 30.0, 0) * 30, '2010-01-01');
答案 1 :(得分:27)
这是在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)
答案 2 :(得分:20)
我知道这是一篇旧帖,但想分享我的答案。这建立在@hbrowser响应的基础上。这就是我想出来的。这将向上或向下舍入到最近的15分钟。
SELECT DATEADD(MINUTE, ROUND(DATEDIFF(MINUTE, 0, GETDATE()) / 15.0, 0) * 15, 0);
通过内联而不是在用户定义的函数内部执行此逻辑,在大型记录集上,您应该体验到更高的性能。
您可以通过将
ROUND
函数交换为使用FLOOR
或CAST expr AS INT
来始终向下舍入或使用CEILING
始终向上舍入来更改舍入方式。
您的个人用例将决定您可能需要使用哪种舍入方式。
以下脚本可用于观察不同舍入技术提供的差异:
注意:为简化输出,每个结果都已转换为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
答案 3 :(得分:6)
您可以将日期舍入到最近的一个季度,例如:
cast(floor(cast(getdate() as float(53))*24*4)/(24*4) as datetime)
将datetime转换为double precesion以避免溢出,double = float(53)。乘以24 * 4,即一天中的季度数。使用floor()舍入到最接近的四分之一倍数,然后除以24 * 4以转换回正常时间。
答案 4 :(得分:5)
尝试了Andomar的答案,并且在30和00处出现了四舍五入的问题 - 所以进行了一些调整,这非常有效:
cast(round(floor(cast(getdate() as float(53))*24*4)/(24*4),5) as smalldatetime)
这将显示最后15分钟的增量,而不是最近的增量,即它不会前进,这正是我需要的。
答案 5 :(得分:2)
最简单的方法:
将分数转换为十进制数除以60。
8/60 = 0.1333333333333333
乘以4
0.1333333333333333 * 4 = 0.5333333333333333
围绕产品:
Round(0.5333333333333333,0) = 1
将整数除以4
1/4 = 0.25 = 15 minutes
如果您希望会议记录只需将其乘以60
0.25*60 = 15
给一个人一条鱼......
答案 6 :(得分:1)
试试这个:
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))
答案 7 :(得分:1)
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)
答案 8 :(得分:1)
- 这是我最喜欢的回合时间
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)
答案 9 :(得分: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,-@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'
答案 10 :(得分:0)
T-SQL中的时间舍入实际上是非常有问题的,并且很多时候都是不准确的。
多年前,我把所有的时间都转移到代码中,而不是使用T-SQL中所有额外的hub-bub来实现它并使其准确发生。代码中的舍入时间更容易,更准确。
如果您遇到T-SQL并且没有支持代码,或者无法访问该代码,请按照前面提到的示例进行操作。否则,我谦虚地建议让代码完成工作。
答案 11 :(得分:0)
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
答案 12 :(得分:0)
在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
答案 13 :(得分:0)
这将四舍五入到最接近的15分钟。您可以将@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
答案 14 :(得分:0)
前提分解以确定你想要的增量,以及60分钟的百分比...然后计算出到达那里所需的增量数量......取INT值(这个剁关闭余数)并且你有它,一个简单的函数来向上或向下舍入到最接近的增量。
简单功能:
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
答案 15 :(得分:0)
DECLARE @Date DATETIME = GETDATE()
SELECT @Date
, DATEADD(ms, 900000 - DATEDIFF(ms, CAST(@Date AS DATE), @Date) % 900000, @Date)