Rails 4中的ActiveRecord查询时间区间

6

我有一个订单表格,其中包含order_date日期时间列。需要一条查询语句,在特定时间范围内获取所有日期的记录。

例如:获取在东部时间上午7点至9点之间所有日期的订单。

类似于:

Order.where('time(order_date) BETWEEN ? AND ?', '7am', '9am')

开始和结束时间来自文本字段,用户可以输入2am、3pm、6am等字符串值。


我不想在日期之间搜索,而是只想查询在某个时间段内的记录,例如每天早上7点到9点之间的记录。 - Arif
你的数据库是什么? - Greg Navis
我正在使用Postgresql。 - Arif
4个回答

5

方法一:EXTRACT

你可以使用EXTRACTorder_date中获取小时数:

Order.where('EXTRACT(hour FROM order_date) BETWEEN ? AND ?', 7, 20)

请注意,我将20(晚上8点)指定为上限。如果我使用21,那么具有21:30时间组件的order_date将匹配,这不是我们想要的。
您可以将上面的查询封装在一个范围内:
class Order < ActiveRecord::Base
  scope :between, -> (start_hour, end_hour) {
    where('EXTRACT(hour FROM order_date) BETWEEN ? AND ?', start_hour, end_hour - 1)
  }
end

还有一些其他问题需要考虑,例如检查start_hourend_hour是否具有有效值(例如-1小时是无效的)。

这种方法很简单,但仅限于整点(您可以添加分钟和秒,但该方法会变得复杂)。

方法2:显式转换为time

Ruby中的Time存储日期和时间。例如:

Time.parse('15:30:45') # => 2017-01-02 15:30:45 +0100

您可以将Time传递给PostgreSQL,并将其显式转换为Postgres time类型:
class Order < ActiveRecord::Base
  scope :between, -> (start_time, end_time) {
    where('order_date::time BETWEEN ?::time AND ?::time', start_time, end_time)
  }
end

这种方法的优点是灵活性。缺点是在处理 UI 中的时间时会更加复杂。范围 (scope) 需要一对 Time 对象。有许多获取它们的方法,例如:Time.parse('12:17')


2
作为一个例子,这将搜索从现在到1个月之前的订单:
Order.where('order_date < ?', Time.now).where('order_date > ?', Time.now - 1.month)

如果您需要将类似于"9am"的字符串转换为对象,则可以使用Time#parse

irb(main):006:0> Time.parse('9 AM')
=> 2016-12-27 09:00:00 -0700

最终的代码可能看起来像这样:
morning = Time.parse('9 AM')
# 2016-12-27 09:00:00 -0700

night = Time.parse('10 PM')
# 2016-12-27 22:00:00 -0700

Order.where('order_date > ?', morning).where('order_date < ?', night)


Order Load (0.2ms)  SELECT `orders`.* FROM `orders ` WHERE (order_date > '2016-12-27 16:00:00.000000') AND (order_date < '2016-12-28 05:00:00.000000')

1
尝试这个。
Order.where(order_date: Time.parse("7am")..Time.parse("9am"))

这似乎是不正确的,因为Ruby中的Time既是日期又是时间。我在本地测试了它是不正确的。生成的查询是SELECT "teachers".* FROM "teachers" WHERE ("teachers"."created_at" BETWEEN $1 AND $2),并且被替换为[["created_at", 2017-01-03 06:00:00 UTC], ["created_at", 2017-01-03 08:00:00 UTC]]。您的查询选择了今天上午7点到9点之间下的订单。@Arif需要任何一天下的订单。 - Greg Navis

1
使用MySql的HOUR函数:

Order.where("HOUR(order_date) between 7 and 9")

请注意查询时使用的时区!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接