【问题标题】:Round to nearest 15 minute interval四舍五入到最近的 15 分钟间隔
【发布时间】:2021-08-02 23:39:09
【问题描述】:

我看到这个问题被问到并回答了存储为日期的时间,但我将小时和分钟的持续时间存储为numeric(4,2)。例如 2.12,是 2 小时 12 分钟。我需要将其四舍五入到最接近的 15 分钟间隔,这样做 (CONVERT([numeric](4,2),round(2.12/(25),(2))*(25))) 不起作用,因为它是以 10 为底并且不正确地舍入时间。任何帮助将不胜感激,谢谢。

编辑:我从示例中寻找的结果是2.25

对于我的用例,持续时间需要以季度表示,

15 分钟 = .25

30 分钟 = .50

45 分钟 = .75

【问题讨论】:

  • 很遗憾,我没有那个选项,我没有日期/时间只有持续时间。
  • 时间应该存储在time数据类型中,而不是numeric
  • @charlieface 是不是一个时间而是一个持续时间的情况?
  • @Joe 以后最好至少提供样本数据和期望的结果。这将消除假设等。
  • 只要总是少于 24 小时,是的。至少,如果您将其存储在numeric 中,请将其存储为带小数的小时,而不是将小数点视为一段文本

标签: sql sql-server tsql rounding


【解决方案1】:

理想情况下,您不会将持续时间存储为小数 - 如果始终少于 24 小时,则应存储为 time,如果可能有多天,则应存储为 datetime2

通过转换为可接受时间格式的字符串来转换为时间。然后使用 here 找到的您最喜欢的解决方案。

select
  -- Original Value
   D.[Value]
   -- As Time
   , T.[Time]
   -- As Time Rounded
   , RT.[Time]
   -- As decimal
   , convert(decimal(9,2),datepart(hour,RT.[Time]) + datepart(minute,RT.[Time]) / 60.0)
from (
  -- Test Values
  values (2.12), (2.02), (0.12)
) D ([Value])
cross apply (
  -- Convert to time datatype
  values (convert(time(0), convert(varchar(8),convert(int, D.[Value])) + ':' + substring(convert(varchar(8),D.[Value] - convert(int, D.[Value])),3,8)))
) T ([Time])
cross apply (
  -- Round using your favourite method
  values (convert(time(0), dateadd(minute, round(datediff(minute, 0, T.[Time]) / 15.0, 0) * 15, 0)))
) RT ([Time]);

【讨论】:

  • 谢谢戴尔,这很有帮助。我希望从示例中获得的结果是 2.25。对于我的用例,持续时间需要以季度表示,15 分钟 = .25、30 分钟 = .50、45 分钟 = .75
  • @Joe Johns 的答案更简单?但那是假设你总是四舍五入,而不是最接近的。
  • 谢谢 Dale .. 我确实假设了。我见过的大多数系统,即时间卡和/或时间和材料,如果不准确的话,都会四舍五入。无论哪种方式 +1
  • @JohnCappelletti 一个非常合理的假设 :) 你一发布我就认为你可能是正确的 - 但取决于 OP。
【解决方案2】:

这是另一个选择

declare @YourTable table (duration numeric(4,2))
Insert Into @YourTable values
 ( 2.12 )
,( 1.30 )
,( 1.55 )

Select  Duration 
       ,NewValue = floor(duration) + ceiling(((duration % 1) * 100 / 60 ) * 4) / 4
 From  @YourTable

结果

Duration    NewValue
2.12        2.250000
1.30        1.500000
1.55        2.000000

【讨论】:

    【解决方案3】:

    您无法对持续时间执行任何计算,因为它不是以 10 为基数,将其转换为以 10 为基数可能会导致精度丢失(例如,您的格式中的 2 小时 1 分钟为 2.01,转换为 2.01666666.. .)

    最好将其转换为总分钟数,然后将其四舍五入并将其转换回您的格式


    declare @duration numeric(4,2) = 2.12;
    
    with 
    cte1 as
    (
        select  tot_mins = (floor(@duration) * 60) 
                         + (@duration * 100) % 100
    ),
    cte2 as
    (
        select  *, tot_mins_rounded = round(tot_mins / 15.0, 0) * 15
        from    cte1
    )
    select  *,
            convert_back_to_your_format = floor(tot_mins_rounded / 60) 
                                        + (tot_mins_rounded % 60) / 100.0
    from    cte2
    

    结果:

    tot_mins tot_mins_rounded convert_back_to_your_format
    132.00 135.000000 2.15000000000

    【讨论】:

    • 谢谢,这确实让我得到了总分钟数,但我需要将小时+分钟四舍五入到最接近的四分之一,例如 2.12(132 分钟)应该是 2.25。
    • 你说I need to round that to the nearest 15 minute interval
    • 要获得“最近的四分之一”,请使用tot_mins_rounded / 60.0
    猜你喜欢
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多