如何使用:比较条件(日期时间)与(日期时间+“天数”)?

问题描述:

我正在构建一个应用程序,用于检查用户何时需要更换其中一辆汽车的油。下面是它如何工作的:如何使用:比较条件(日期时间)与(日期时间+“天数”)?

  1. 用户输入他的车(例如“福特野马”)
  2. 用户进入汽车将在一个换油运行时的名称(例如3.months)
  3. 用户将汽车保存到数据库
  4. 对所有其他汽车重复上述过程。 (是的,这是一个有钱的用户;)

现在,当用户回到网站时,他想看到他所有需要更换机油的汽车列表。然后他改变石油并更新'oil_changed_at'属性。

我用下面列的汽车模型:

title:string 
oil_changed_at:datetime 
oil_expiration_timeframe:integer 

我的问题:什么是存储该“oil_expiration_timeframe”和我应该什么样的首选方式:条件看起来就像当我想要获得所有需要更换机油的汽车清单?

请记住oil_expiration_timeframe可能会从几天到几年不等。它永远不会少于一天,所以我认为我可以将该天数存储在该领域。但是,我不确定如何在查询中合并整数和日期时间。

如果您索引您的oil_changed_at列,以下方法是有效的。

Car.all(:conditions => [ 
    "oil_changed_at > DATE_SUB(?, INTERVAL oil_expiration_timeframe day)", Time.now 
]) 

更好的方法是新的一列(next_oil_change_date)添加到汽车模型来存储下次换油日期和更新后的变化对汽车模型的山坳。

class Car < ActiveRecord::Base 
    before_save :set_next_oil_change_date 

    def set_next_oil_change_date 
    self.next_oil_change_date = next_oil_change_date + 
            oil_expiration_timeframe.days 
    end 
end 

现在你可以写你的查询为:

Car.all(:conditions => [ 
    "next_oil_change_date > ? ", Time.now 
]) 

不要忘记指数next_oil_change_date列。

+0

感谢您的回答。就像你和wuputah建议我只是创建一个next_oil_change_date列,以便我的代码不会依赖任何特定类型的数据库。 – Marc 2010-08-28 02:31:14

将数字添加到日期时间会将日期添加到日期中。例如:

irb(main):005:0> DateTime.now.to_s 
=> "2010-08-27T18:32:36-06:00" 
irb(main):006:0> (DateTime.now + 7).to_s 
=> "2010-09-03T18:32:48-06:00" 

所以我建议坚持原来的计划,保持偏移量存储为数天。

+0

是的,我知道这一点。但是,我将如何在查询中使用它?我需要使用DateTime.now(一个Ruby函数)和oil_expiration_timeframe(表中的一列)进行计算。我不确定如何将这两者结合成条件语句。 – Marc 2010-08-28 01:16:54

这确实是一个知道一堆SQL日期函数的问题。在MySQL中,它看起来像这样:

:conditions => 
    "DATE_ADD(DATE(oil_changed_at), 
      INTERVAL oil_expiration_timeframe DAY) <= CURDATE()" 

唯一的缺点是没有优化此查询的好方法。如果性能成为问题,则可能最容易将当前的到期日期存储在数据库中。

+0

感谢您的建议。我更喜欢数据库不可知的方法,但这是一个很好的起点。 – Marc 2010-08-28 02:23:26

+0

我喜欢Kandada对查询的方法(改为使用DATE_SUB),但我相信数据库不可知论经常被高估,除非这样做是明确的要求(一项艰巨的任务!)。我相信任何大型Web应用程序都需要优化他们的代码以选择RDBMS(和/或其他存储解决方案)。不幸的是,ANSI SQL标准在数据库中如此糟糕的实现,但事实如此。 – wuputah 2010-08-28 06:06:35

基于wuputah的MySQL查询的代码,我想出了SQLite的以下内容:

:conditions => 'date(oil_changed_at, oil_expiration_timeframe||" days") <= date("now")' 

当然,数据库无关的方法仍然是首选。

+0

感谢您的建议。我更喜欢数据库不可知的方法,但这是一个很好的起点。我可能会多加一列,让我的生活更轻松。 我打算接受KandadaBoggu的答案,因为它有点广泛,可能会帮助其他人进入此页面,但我真的很感谢您花时间回答。再次感谢! – Marc 2010-08-28 02:33:56