将日期时间值舍入到最接近的半小时

时间:2013-10-17 13:02:07

标签: sql sql-server tsql

我需要将datetime2值向下舍入到最近的半小时。例如'10 / 17/2013 12:10:00.123'将向下舍入到'10 / 17/2013 12:00:00.0'和'10 / 17/2013 12:34:17.123'将向下舍入到10/17 / 2013 12:30:00.0'。我的第一个想法是创建一个UDF,它可以打破日期和时间,并以这种方式进行。但是,我想知道这样的事情是否可以在单个T-SQL语句中完成?

我正在使用SQL Server 2012,该列的数据类型是dateTime2(无法转换为float !!)

7 个答案:

答案 0 :(得分:11)

Ian的答案很好,但它包含了不必要的转换。我建议

SELECT CONVERT(smalldatetime, ROUND(CAST([columnname] AS float) * 48.0,0,1)/48.0) FROM [tableName]

如果要舍入到最近的半小时而不是总是向下舍入,请使用

SELECT CONVERT(smalldatetime, ROUND(CAST([columnname] AS float) * 48.0,0)/48.0) FROM [tableName]

答案 1 :(得分:1)

这个怎么样

declare @d datetime = '2013-05-06 12:29.123'
select 
case 
    when datepart(minute, @d) < 30 then cast(dateadd(minute, -datepart(minute,@d)-datepart(second,@d), @d) as smalldatetime)
    when datepart(minute, @d) >= 30 then cast(dateadd(minute, -datepart(minute,@d)-datepart(second,@d)+30, @d) as smalldatetime)
end

答案 2 :(得分:0)

select cast(floor(cast(
    cast('10/17/2013 12:34:00' as datetime) 
as float(53)) * 48) / 48 as datetime)

修改

如果使用smalldatetime来避免额外的精度,那么效果会更好

select cast(floor(cast(
    cast('2012-01-02 11:33:14.097' as smalldatetime) 
as float(53)) * 48) / 48 as smalldatetime)

答案 3 :(得分:0)

这是一种方法:

update t set
  d = dateadd(minute,datediff(minute,'19000101',d)/30*30,'19000101');

答案 4 :(得分:0)

当我需要向下舍入到最接近的5分钟间隔时,我使用的方法略有不同。可能有一种方法可以进一步简化这一点,但至少这让我得到了我需要的东西。

DECLARE @now datetime = GETDATE()

SELECT @now as cur_datetime, DATEADD(MINUTE, -(DATEDIFF(MINUTE,DATEADD(HOUR,DATEDIFF(HOUR,0,@now), 0),DATEADD(MINUTE,DATEDIFF(MINUTE,0,@now), 0)) % 5), DATEADD(MINUTE,DATEDIFF(MINUTE,0,@now), 0)) as round_down_to_nearest_5_minute_mark

答案 5 :(得分:0)

@Twinkles的答案在SQL Server中效果很好,可以将其舍入到最接近的半小时。

但是,在开发中,强烈建议使用FLOOR舍入到 最后半小时

SELECT CONVERT(datetime, FLOOR(CAST([columnname] AS float) * 48.0)/48.0) FROM [tableName]

答案 6 :(得分:0)

您可以使用 DATETIME2FROMPARTS 来重建日期。要将分钟向下四舍五入到 30 分钟间隔,请使用公式 minutes intdiv 30 * 30

SELECT
    dt2,
    DATETIME2FROMPARTS(
        DATEPART(year, dt2),
        DATEPART(month, dt2),
        DATEPART(day, dt2),
        DATEPART(hour, dt2),
        DATEPART(minute, dt2) / 30 * 30,
        0,
        0,
        0
    )
FROM (VALUES
    -- generic datetime2
    (SYSDATETIME()),
    -- 30 minute boundary
    ('2001-01-01 00:29:59.9999999'),
    ('2001-01-01 00:30:00.0000000'),
    ('2001-01-01 00:30:00.0000001'),
    -- min and max date
    ('0001-01-01 00:00:00.0000000'),
    ('9999-12-31 23:59:59.9999999')
) AS v(dt2)