Rails - 两个日期之间的日期?

时间:2011-01-23 16:42:36

标签: ruby-on-rails ruby-on-rails-3

我正在创建一个系统,需要确保计划中的“旅行”不会超过一圈。为此,我尝试验证start_date和end_date,以确保它们不在另一次旅行的开始和结束日期之内。

class TripdateValidator < ActiveModel::EachValidator

  def validate_each(object, attribute, value)

      # Check value exists as end_date is optional
      if value != nil

          parsed_date = Date.parse(value)

          # is the start date within the range of anything in the db
         trips = Trip.where(['start_date >= ? AND end_date <= ? AND user_id = ?', parsed_date, parsed_date, object.user_id])

        # overlapping other trips, aghhh
        object.errors[attribute] << 'oh crap' if trips
      end
  end
end

日期来自type =“date”字段,该字段由jQuery UI Datepicker提供支持,包含格式2011-01-01。这就是2011-01-30 00:00:00 UTC的轨道,我还不完全理解。

如果我尝试对此值使用Date.parse(),则会出现错误:

  

TripsController中的TypeError #create

     

$ _ value需要为String(nil given)

     

Rails.root:
  /Users/phil/Sites/travlrapp.com
  应用程序跟踪|框架追踪|
  完整跟踪

     

应用程序/模型/ trip.rb:29:在
  validate_each'
app/controllers/trips_controller.rb:75:in
创建'
  应用程序/控制器/ trips_controller.rb:74:在
  `create'

每当我运行查询时,都不会返回任何内容。这可能是一个日期格式问题,我的逻辑是破碎还是我做了一些非常愚蠢的事情?被困在这一段时间谷歌没有帮助。

编辑人们关注的是Date.parse错误,但这不是主要问题。我陷入困境的是,当一切都是完全不同的格式时,我不明白如何进行日期比较。

我已经为Chronic.parse()交换了Date.parse(),现在我正在生成以下SQL查询:

 SELECT "trips".* FROM "trips" WHERE (start_date >= '2011-01-26 00:00:00.000000' AND end_date <= '2011-01-26 00:00:00.000000' AND user_id = 19)

这不会返回任何内容。我测试的日期是:

开始时间:2011-02-17 00:00:00.000000 结束时间:2011-02-21 00:00:00.000000

看到我认为日期格式正确,现在看起来更像是一个逻辑问题。我怎么能验证重叠日期&gt;。

9 个答案:

答案 0 :(得分:10)

Squeel power FTW !!!我相信你一定会喜欢它

$ gem install squeel

model.rb

Model.where{date_colum > 10.years.ago & date_column < DateTime.now}

答案 1 :(得分:3)

我主要是回复你的编辑,我认为你没有得到任何结果有两个原因:

首先:我怀疑你的解析器给你DateTime对象,而你真的只想要简单的Date对象。将DateTime传递给Rails的SQL查询生成器,它会为您提供一个'YYYY-MM-DD hh.mm.ss.uuu...'字符串,而数据库只需要一个简单的'YYYY-MM-DD'字符串来进行日期列比较;数据库日期解析器失败,返回NULL,所有与NULL失败的比较等等,你得到一个空的结果集。

parsed_date更改为parsed_date.to_date,您应该在这方面做得好。

第二:看一下你的SQL,特别是这个块start_date >= ? AND end_date <= ?。在我看来,如果你要检查的行程的开始日期晚于结束日期,它只会检测到碰撞。

所以请尝试我个人喜欢的start_date <= ? AND end_date >= ?? BETWEEN start_date AND end_date,因为它更具可读性。

希望这有帮助!

答案 2 :(得分:3)

对于重叠验证,您可以尝试使用其中一个宝石https://github.com/chrisb87/range_validatorhttps://github.com/robinbortlik/validates_overlap

答案 3 :(得分:3)

对于那些登陆的人,请查看范围条件Rails guides

Client.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)

这将产生以下SQL:

SELECT * FROM clients WHERE (clients.created_at BETWEEN '2008-12-21 00:00:00' AND '2008-12-22 00:00:00')

因此,您可以使用范围搜索两个日期之间的字段。

答案 4 :(得分:2)

我更喜欢:

Model.where{date_colum >> (10.years.ago..Datetime.now)}

答案 5 :(得分:0)

您是否尝试过使用TimeZone课程:

parsed_date = Time.zone.parse(value)

这是文档:

http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html#method-i-parse

答案 6 :(得分:0)

我会记录“值”并查看它是否远程接近Date.parse()可以处理的内容。如果它看起来可以解析,看看Date.parse是否在irb中工作,如果是,请在控制台env(./script/console或rails c)中查看它的应用程序。那应该追查问题。

答案 7 :(得分:0)

这个怎么样?

overlaps = Trip.where(
    "(DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0",
    self.end_date,
    self.start_date
)

它基本上是这样说的:

  

如果每个开始日期都看向另一个结束日期,那么他们是否正在寻找   在同一个方向?然后他们重叠。

答案 8 :(得分:0)

您可以使用cover method

如果所选范围之间的数据为假,则返回true