【问题标题】:Rails 4 ActiveRecord Querying Between TimesRails 4 ActiveRecord在时间之间查询
【发布时间】:2016-12-27 06:46:20
【问题描述】:

我有一个带有 order_date 日期时间列的订单表。需要一个查询来获取特定时间范围内所有日期的记录。

示例:获取美国东部时间上午 7 点到上午 9 点之间所有日期的订单。

类似:

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

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

【问题讨论】:

  • 我不想在日期之间进行搜索,我只想在时间之间进行查询,即每天早上 7 点到 9 点之间的记录
  • 你的数据库是什么?
  • 我正在使用 Postgresql

标签: ruby ruby-on-rails-4


【解决方案1】:

方法一:EXTRACT

您可以使用EXTRACTorder_date 获取小时:

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

请注意,我将 20(晚上 8 点)指定为上限。如果我使用21,那么order_date 与21:30 的时间部分将匹配,这不是我们想要的。

您可以将上面的查询包装在一个范围内:

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 中处理时间有点复杂。范围需要一对 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')
    

    【讨论】:

      【解决方案3】:

      试试这个

      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 需要任何天的订单。
      【解决方案4】:

      使用MySqlHOUR函数:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-09-04
        • 2011-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-19
        相关资源
        最近更新 更多