【问题标题】:Calculate time difference between two timestamp with additional conditions in postgres在postgres中使用附加条件计算两个时间戳之间的时间差
【发布时间】:2020-09-08 14:30:07
【问题描述】:

我想根据 postgres 中的开始和结束时间来获取两个时间戳字段之间的小时、分钟和秒的总时间差

supermarket 具有字段opening_timeclosing_time

orders 具有字段order_idarrived_datepicked_date

我想计算挑选订单所花费的总时间。 (只有超市开门才可以取单,但当天随时下单排队)

条件:总拣货时间应考虑店铺的开闭时间计算。

例子

考虑opening_time09:00:00closing_time22:00:00

案例1:如果一个订单在2020-09-08 10:00:00到达并在2020-09-08 12:00:00被拣货,那么总拣货时间应该是02 hours

案例2:如果订单在2020-09-08 06:00:00到达并在2020-09-08 12:00:00被拣选,那么考虑到开放时间,总拣货时间应该是03 hours,而不是06 hours

案例 3:如果订单在2020-09-08 23:00:00 到达并在第二天在2020-09-09 10:00:00 取货,那么考虑到关闭和打开时间,总的取货时间应该是01 hour

【问题讨论】:

  • supermarket.opening_timesupermarket.closing_time 的数据类型是什么?
  • @Mike Organek,它的时区时间

标签: postgresql


【解决方案1】:

看起来有点复杂,特别是如果范围可能超过 24 小时。最安全的解决方法可能是一种蛮力方法,它生成范围内的所有时间,然后进行过滤和聚合:

select s.*, x.*
from supermarket s
cross join lateral (
    select count(*) no_hours
    from generate_series(s.opening_time, s.closing_time, '1 hour') x(x_time)
    where x_time::time >= '09:00:00'::time and x_time::time < '22:00:00'::time
) x

这假设开始和结束日期被截断为小时,如您的示例中所示。如果你想处理分钟,那么:

select s.*, x.*
from supermarket s
cross join lateral (
    select count(*) no_minutes
    from generate_series(s.opening_time, s.closing_time, '1 minute') x(x_time)
    where x_time::time >= '09:00:00'::time and x_time::time < '22:00:00'::time
) x

【讨论】:

  • 对不起,我没有完全理解你的方法。你能告诉我查询的 x_time 是多少
  • @user3614760:它保存着开盘和关盘之间的一系列日期。
【解决方案2】:

时间戳可以简单地减去得到一个间隔。

test=# select '2020-09-08 12:00:00'::timestamp - '2020-09-08 10:00:00'::timestamp;
 ?column? 
----------
 02:00:00
(1 row)

然后可以使用to_char 格式化该间隔。

test=# select to_char('2020-09-08 12:00:00'::timestamp - '2020-09-08 10:00:00'::timestamp, 'HH24 hours MI "minutes"');
       to_char       
---------------------
 02 hours 00 minutes
(1 row)

要考虑开闭时间得到正确的间隔,你需要一点逻辑来计算出实际的拣货开始时间。

select
case
when arrived_date::time < opening_time
  -- It arrived before you're open. Start when you open that day.
  arrived_date::date + opening_time
when arrived_date::time > closing_time
  -- It arrived after you closed. Start when you open tomorrow.
  arrived_date::date + '1 day'::interval + opening_time
else
  -- It arrived while you're open. Start when it arrives.
  arrived_date
end as picking_start

诀窍是将arrived_date 转换为time,截断日期部分,以与开始和结束时间进行比较。同样,我们可以将arrived_date 转换为date 并仅使用日期部分,然后添加开放时间。这假定 arrived_datetimestamp 并且 opening_timeclosing_timetime 列。

这可以是condensed into a function,以便于使用。

【讨论】:

  • 谢谢,@Schwern。当我没有附加条件时它会起作用。对于案例 2 和案例 3,它不会给出预期的结果
  • 谢谢。当我们没有超过 1 天的时间间隔时,它工作正常。如果订单在 5 天后被拣选,我该如何管理,因为第二个时间将管理唯一的 1 天条件
  • @user3614760 好问题。我想不出一种优雅的方式。我建议将其作为自己的问题提出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-13
  • 1970-01-01
  • 2016-12-17
相关资源
最近更新 更多