给定两个时间戳,计算这些日期之间经过的工作小时数

时间:2018-03-09 16:00:04

标签: google-bigquery

给定表start_time, end_time中的两个时间戳计算它们之间发生的总工作时间。

工作时间在您选择的单独表格中定义。

2 个答案:

答案 0 :(得分:6)

假设您有一个工作时间表,这里是 Snowflake SQL 中的一个解决方案:

select
  t.id
  , sum(datediff(‘second’, 
               -- calculate the max of the two start time
               (case when t.start <= 
                          w.working_day_start_timestamp
                     then w.working_day_start_timestamp
                     else t.start
                end),
               -- calculate the min of the two end times
               (case when t.end >= 
                          w.working_day_end_timestamp
                     then w.working_day_end_timestamp
                     else t.end 
                end)
               )) / 3600 -- convert to hourly
  as working_hour_diff
from 
  working_days_times w,
  cross join time_intervals t
where -- select all intersecting intervals
  (
   t.start <= w.working_day_end_timestamp
   and
   t.end >= w.working_day_start_timestamp
  )
and -- select only working days
  w.is_working_day
group by
  t.id

这里有一篇文章,详细介绍了在 SQL 中以及作为 Snowflake 中的 Javascript UDF 实现此功能的更多细节:

https://medium.com/dandy-engineering-blog/how-to-calculate-the-number-of-working-hours-between-two-timestamps-in-sql-b5696de66e51

答案 1 :(得分:3)

下面的示例适用于BigQuery Standard SQL

#standardSQL
WITH `project.dataset.working_hours` AS (
  SELECT 1 weekday, 'Sun' DAY, NULL start_time, NULL end_time UNION ALL
  SELECT 2, 'Mon', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
  SELECT 3, 'Tue', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
  SELECT 4, 'Wed', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
  SELECT 5, 'Thu', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
  SELECT 6, 'Fri', TIME(9, 0, 0), TIME(17, 0, 0) UNION ALL
  SELECT 7, 'Sat', TIME(9, 0, 0), TIME(15, 0, 0) 
), `project.dataset.availability` AS (
  SELECT 'Tom' name, TIMESTAMP '2018-01-10 12:38:04' start_time, TIMESTAMP '2018-02-11 10:38:04' end_time UNION ALL
  SELECT 'Mike', TIMESTAMP '2018-01-01 12:35:00', TIMESTAMP '2018-01-01 14:35:00' UNION ALL
  SELECT 'Sam', TIMESTAMP '2018-01-06 12:35:00', TIMESTAMP '2018-01-07 14:35:00' 
), full_days_minutes AS (
  SELECT name, 
    SUM(TIME_DIFF(h.end_time, h.start_time, MINUTE)) minutes
  FROM `project.dataset.availability` a, 
    UNNEST(GENERATE_DATE_ARRAY(DATE(start_time), DATE(end_time))) DAY
  JOIN `project.dataset.working_hours` h
    ON h.weekday = EXTRACT(DAYOFWEEK FROM DAY)
  GROUP BY name
), corrections AS (
  SELECT name,
    IFNULL(CASE -- correction for start time 
      WHEN TIME(a.start_time) > x.end_time THEN TIME_DIFF(x.end_time, x.start_time, MINUTE)
      WHEN TIME(a.start_time) < x.start_time THEN 0
      ELSE TIME_DIFF(TIME(a.start_time), x.start_time, MINUTE)
    END, 0) + 
    IFNULL(CASE -- correction for end time 
      WHEN TIME(a.end_time) < y.start_time THEN TIME_DIFF(y.end_time, y.start_time, MINUTE)
      WHEN TIME(a.end_time) > y.end_time THEN 0
      ELSE TIME_DIFF(y.end_time, TIME(a.end_time), MINUTE)
    END, 0)
    AS correction
  FROM  `project.dataset.availability` a
  JOIN `project.dataset.working_hours` x ON x.weekday = EXTRACT(DAYOFWEEK FROM a.start_time)
  JOIN `project.dataset.working_hours` y ON y.weekday = EXTRACT(DAYOFWEEK FROM a.end_time)
)
SELECT name, minutes - correction AS elapsed_minutes, 
  ROUND((minutes - correction) / 60, 2) elapsed_hours
FROM full_days_minutes JOIN corrections USING(name)  

结果为

Row name    elapsed_minutes elapsed_hours    
1   Tom              12,622        210.37    
2   Mike                120          2   
3   Sam                 145          2.42         

注意:代码假定在availability和working_hours表中的start_time&lt; = end_time