获取在特定时间之后创建的记录

时间:2016-10-09 08:39:16

标签: ruby-on-rails postgresql activerecord

假设我有一个Event模型,其中date_time字段代表事件发生的日期时间,我希望看到所有事件,例如“晚上10点后”或“在多个日期之前的早上7点之前。我怎么能这样做?

我的第一个想法是这样的:

scope :after_time ->(time){ where("events.date_time::time between ?::time and '23:59'::time", time) }

但这不起作用,因为日期以UTC格式存储并由ActiveRecord转换为应用程序的时区。

所以,让我说我在阿德莱德当地时间下午5点之后搜索活动。最终的查询是这样的:

WHERE (events.date_time::time between '2016-10-09 06:30:00.000000'::time and '23:59'::time)

也就是说,因为我的时区是+10:30(阿德莱德时间),现在它正在尝试在早上6:30到午夜之间进行计算,真正需要在早上6:30到下午1:30之间找到创建的时间。

现在,特别是对于这个例子,我可能会共同解决一些问题,以确定“午夜”时间需要给出的时区差异。但如果那段时间跨越午夜时间,那么between <given time> and <midnight in Adelaide>计算将不会起作用。所以解决方案就是破产。

更新:

我已经设法通过反复试验获得了我想要的结果,但我不确定我到底知道到底发生了什么。

scope :after_time, ->(time) { time = time.strftime('%H:%M:%S') where_clause = <<-SQL (events.date_time at time zone 'UTC' at time zone 'ACDT')::time between ? and '23:59:59' SQL joins(:performances).where(where_clause, time) }

它基本上将所有内容都转换为一个时区,因此每行的查询最终看起来像WHERE '20:30:00' between '17:00:00' and '23:59:59',所以我不必担心跨越午夜的时间。

即便如此,我觉得这可能是一种正确的方法,所以我愿意接受建议。

2 个答案:

答案 0 :(得分:1)

这可能对您有帮助,然后您不需要转换DB的每个日期,而是可以将参数化时间戳转换为UTC时间:

scope :after, ->(start_time) { where('created_at::time > :time', time: start_time.utc.strftime('%H:%M:%S')) }

现在, 例如我有3个事件用于以下时间戳(全部以UTC表示):

  1. 2013-04-11 11:43:43
  2. 2013-04-11 15:10:40
  3. 2013-04-12 07:39:26
  4. 然后你可以打电话:

    start_time = Time.zone.parse('2016-01-01 20:00:00')
    # => Fri, 01 Jan 2016 20:00:00 ACDT +10:30
    Event.after(start_time) # this will return 2 events(1, 2)
    

    查询将是:

    SELECT "events".* FROM "events" WHERE (created_at::time > '09:30:00')
    
      

    注意:如果您将此查询与任何其他具有ActiveRecord::StatementInvalid: PG::AmbiguousColumn: ERROR: column reference "created_at" is ambiguous列的模型

    一起使用,则会引发错误created_at

答案 1 :(得分:0)

检查这是否适合您,

s = DateTime.now.change(hour: 6, min: 30).utc
e = Date.today.end_of_day.utc
Event.where("date_time::time between ?::time and ?::time", s, e)