假设我有一个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'
,所以我不必担心跨越午夜的时间。
即便如此,我觉得这可能是一种正确的方法,所以我愿意接受建议。
答案 0 :(得分:1)
这可能对您有帮助,然后您不需要转换DB的每个日期,而是可以将参数化时间戳转换为UTC时间:
scope :after, ->(start_time) { where('created_at::time > :time', time: start_time.utc.strftime('%H:%M:%S')) }
现在, 例如我有3个事件用于以下时间戳(全部以UTC表示):
然后你可以打电话:
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)