【问题标题】:Rails - Is a date between two dates?Rails - 是两个日期之间的日期吗?
【发布时间】:2011-01-23 16:42:35
【问题描述】:

我正在创建一个系统,该系统需要确保计划中的“旅行”不会重叠。为此,我正在尝试验证 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 年 1 月 30 日 00:00:00 UTC 时出现了问题,我不完全理解。

如果我尝试在这个值上使用 Date.parse() 它会给出错误:

TripsController#create 中的类型错误

$_ 值必须是字符串(给定 nil)

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

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

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

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

我已将 Date.parse() 替换为 Chronic.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

我认为现在日期格式正确,这似乎更像是一个逻辑问题。我怎么能验证重叠的日期>。

【问题讨论】:

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


    【解决方案1】:

    Squeel 电源 FTW!!!相信你会喜欢的

    $ gem install squeel

    模型.rb

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

    【讨论】:

    • 这是一个很好的解决方案,除了上面的可能必须是:Model.where{(date_colum &gt; 10.years.ago) &amp; (date_column &lt; DateTime.now)}
    【解决方案2】:

    对于那些登陆这里的人,请检查范围条件上的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')
    

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

    【讨论】:

    • 这很好用,它是 Rails 的一部分。我什至可以使用字符串:where(created_at:'2016-05-12 09:00'..'2016-05-12 10:00')
    【解决方案3】:

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

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

    parsed_date 更改为parsed_date.to_date,您在这方面应该没问题。

    第二:看看你的 SQL,特别是这个块 start_date &gt;= ? AND end_date &lt;= ?。在我看来,只有当您检查的行程的开始日期晚于结束日期时,它才会检测到碰撞。

    所以试试start_date &lt;= ? AND end_date &gt;= ?? BETWEEN start_date AND end_date,我个人更喜欢它,因为它更具可读性。

    希望这会有所帮助!

    【讨论】:

      【解决方案4】:

      【讨论】:

        【解决方案5】:

        我更喜欢:

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

        【讨论】:

          【解决方案6】:

          您是否尝试过 TimeZone 类:

          parsed_date = Time.zone.parse(value)
          

          这是文档:

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

          【讨论】:

          • 我现在正在使用 Chronic::parser() 但我仍然有比较查询中的日期的问题。我假设如果我将 ActiveRecord 传递给 DateTime 对象,它将能够转换它。有还是没有?无论哪种方式,当我的结果应该有数据时,它们都是空的。
          • 一个奇怪的事情是错误消息说有一个 nil 值而不是一个字符串。如果该错误是由 parse 调用引发的,那么从您提供的代码来看,这似乎是不可能的。也许给我们完整的堆栈跟踪会有所帮助。
          • 奇怪,堆栈跟踪清楚地表明 nil 作为第一个参数发送给 Data.parse。我会说该错误并非源自您发布的验证器代码。 app/models/trip.rb 的第 29 行(或带有最新堆栈跟踪的第 30 行)还有其他内容吗?
          • 没有任何影响值。如果我在 Date.parse() 之前添加一个 puts 值,我会得到“2011-01-26 00:00:00 UTC”,奇怪的是这不是 POST 中的值,因为我只发送 2011-01-26。 d.pr/lWPU
          • 真的很奇怪!什么是值类?
          【解决方案7】:

          我会记录“值”并查看它是否远程接近 Date.parse() 可以处理的东西。如果它看起来可解析,请查看 Date.parse 是否在 irb 中对其有效,如果可以,请在控制台环境(./script/console 或 rails c)中为您的应用检查它。这应该可以找出问题所在。

          【讨论】:

          • 这不是这里的主要问题。我需要以某种方式解析日期,并制作一些东西,rails 可以用来将我的日期与数据库中的日期进行比较。正如我所说,字符串是 2011-01-30 00:00:00 UTC,date.parse 应该可以使用。一旦被解析,我怎么能把它变成我的本地 SQLite 以及 Heroku 上的 Postgres 都会满意的格式?
          【解决方案8】:

          这个怎么样?

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

          它基本上是这样说的:

          如果每个开始日期都向对方的结束日期看,他们是否在看 在同一个方向?然后它们重叠。

          【讨论】:

            【解决方案9】:

            您可以使用cover method

            如果所选范围内的数据返回true,否则返回false

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-08-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多