将字符串中的时间转换为小时数

convert time in string to number of hours

我正在尝试将字符串中的时间转换为小时数。

例如

| Hours in text       | Number of hours |
| ------------------- | --------------- |
| 1 minute            | 0.02            |
| 30 minutes          | 0.5             |
| 2 Hours 15 Minutes  | 2.25            |
| 8 Hours             | 8               |
| 4 Hours 30 Minutes  | 4.5             |
| 1 Hour              | 1               |

DECLARE @tabvar TABLE(TimeInText VARCHAR(100));

INSERT INTO @tabvar(TimeInText)
SELECT '1 minute' UNION ALL
SELECT '30 minutes' UNION ALL
SELECT '2 Hours 15 Minutes' UNION ALL
SELECT '8 Hours' UNION ALL
SELECT '4 Hours 30 Minutes' UNION ALL
SELECT '1 Hour'
    
SELECT CONVERT(CHAR(5), DATEADD(MINUTE, 60 * NULLIF(RTRIM(LTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(TimeInText, ' Hours ', '.'), ' Hours', '.'), ' Hour', '.00'), ' Minutes', ''), ' ', ''))), ''), 0), 108)
FROM @tabvar

尝试转换 8 小时时,我卡住了“8”。而不是“8”

漂亮。 T-SQL forté 是 而不是 字符串操作,您选择将时间存储为描述性字符串充其量是一个有问题的设计选择。但是,我也觉得将值设置为 decimal 也是一个坏主意;您应该使用 time 数据类型。

也就是说,这 对所提供的示例数据有效

SELECT tv.TimeInText,
       ISNULL(CONVERT(decimal(5,3),LEFT(tv.TimeInText,NULLIF(h.CI,0)-1)),0) + ISNULL((CONVERT(decimal(5,3),LEFT(s.m,NULLIF(m.CI,0)-1)) / 60),0) AS NumberOfHours
FROM @tabvar tv
     CROSS APPLY (VALUES(CHARINDEX('hour',tv.TimeInText)))h(CI)
     CROSS APPLY (VALUES(CHARINDEX(' ',tv.TimeInText,NULLIF(h.ci,0))))ws(ci)
     CROSS APPLY (VALUES(STUFF(tv.TimeInText,1,ISNULL(ws.ci,0),'')))s(m)
     CROSS APPLY (VALUES(CHARINDEX('minute',s.m)))m(CI);

或者不使用 VALUES 使表达式易于阅读...(享受这个 mess ):

SELECT tv.TimeInText,
       ISNULL(CONVERT(decimal(5,3),LEFT(tv.TimeInText,NULLIF(CHARINDEX('hour',tv.TimeInText),0)-1)),0) + ISNULL((CONVERT(decimal(5,3),LEFT(STUFF(tv.TimeInText,1,ISNULL(CHARINDEX(' ',tv.TimeInText,NULLIF(CHARINDEX('hour',tv.TimeInText),0)),0),''),NULLIF(CHARINDEX('minute',STUFF(tv.TimeInText,1,ISNULL(CHARINDEX(' ',tv.TimeInText,NULLIF(CHARINDEX('hour',tv.TimeInText),0)),0),'')),0)-1)) / 60),0) AS NumberOfHours
FROM @tabvar tv;

db<>fiddle

select *, format(datepart(hour, _time) + datepart(minute, _time)/60., '0.##') as NumberOfHours
from
(
select *, 
    timefromparts
    (
    left(TimeInText, charindex(' hour', TimeInText)), 
    substring(TimeInText, charindex('minute', TimeInText)-3, 3), 
    0, 0, 0
    ) as _time
from @tabvar
) as t;

另一种选择

例子

Select A.* 
      ,NewVal = convert(decimal(10,2),
                        case when Pos2 like 'Hour%' then try_convert(int,Pos1)+isnull(try_convert(decimal(10,2),Pos3),0)/60 
                        else try_convert(decimal(10,2),Pos1)/60 end
                       )
 From  YourTable A
 Cross Apply (
                Select Pos1 = trim(JSON_VALUE(S,'$[0]'))
                      ,Pos2 = trim(JSON_VALUE(S,'$[1]'))
                      ,Pos3 = trim(JSON_VALUE(S,'$[2]'))
                      ,Pos4 = trim(JSON_VALUE(S,'$[3]'))
                 From  ( values ( '["'+replace(replace([Hours in text],'"','\"'),' ','","')+'"]' ) ) A(S)
             ) B

Returns

Hours in text       NewVal
1 minute            0.02
30 minutes          0.50
2 Hours 15 Minutes  2.25
8 Hours             8.00
4 Hours 30 Minutes  4.50
1 Hour              1.00