Rails ActiveRecord дата между


171

Мне нужно запросить комментарии, сделанные за один день. Поле является частью стандартных временных меток, является created_at. Выбранная дата исходит от date_select.

Как я могу использовать ActiveRecordэто сделать?

Мне нужно что-то вроде:

"SELECT * FROM comments WHERE created_at BETWEEN '2010-02-03 00:00:00' AND '2010-02-03 23:59:59'"

Ответы:


402

Просто обратите внимание, что принятый в настоящее время ответ устарел в Rails 3. Вместо этого вам следует сделать следующее:

Comment.where(:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day)

Или, если вы хотите или должны использовать чисто строковые условия , вы можете сделать:

Comment.where('created_at BETWEEN ? AND ?', @selected_date.beginning_of_day, @selected_date.end_of_day)

9
Day.where (: reference_date => 6.months.ago..Time.now) работает, спасибо
boulder_ruby

4
Разве это не создало бы объект огромного диапазона?
Каспер Граббе,

3
@KasperGrubbe, если бы вы использовали диапазон сам по себе, он бы использовал, но Rails просто использует первое и последнее значения
Dex

4
@KasperGrubbe @Dex Это не Rails, который делает это. Класс Range в Ruby сохраняет только нижнюю и верхнюю границы. Это нормально работает в irb: 1..1000000000000мне неясно, что вы подразумеваете под «использованием диапазона самостоятельно»
Коннор Кларк,

11
+1 Мы также можем сделать это масштабом: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte

48

Я бы лично создал область, чтобы сделать ее более читабельной и многократно используемой:

В вашем Comment.rb вы можете определить область действия:

scope :created_between, lambda {|start_date, end_date| where("created_at >= ? AND created_at <= ?", start_date, end_date )}

Затем запрос создан между:

@comment.created_between(1.year.ago, Time.now)

Надеюсь, поможет.


4
Очень чистый подход ... идеально!
Джозеф Н.

Назад, чтобы подтвердить этот ответ, потому что я искал именно эту проблему. Неправильно угадал по синтаксису, предположил, #between?принял диапазон.
ТАСС

28

В Rails 5.1 появился новый вспомогательный метод date all_day, см. Https://github.com/rails/rails/pull/24930.

>> Date.today.all_day
=> Wed, 26 Jul 2017 00:00:00 UTC +00:00..Wed, 26 Jul 2017 23:59:59 UTC +00:00

Если вы используете Rails 5.1, запрос будет выглядеть так:

Comment.where(created_at: @selected_date.all_day)

1
Славный. На самом деле это часть гема ActiveSupport (а впоследствии и всей экосистемы ActiveRecord), поэтому он работает и за пределами Rails! Просто require 'active_record'и все готово!
Мастер уток

24

Этот код должен работать для вас:

Comment.find(:all, :conditions => {:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day})

Для получения дополнительной информации взгляните на расчет времени

Примечание. Этот код устарел . Используйте код из ответа, если вы используете Rails 3.1 / 3.2


Хорошо, но из формы я получаю это: {"writ_at (4i) "=>" 18 ", "writ_at (5i)" => "56", "content" => "rrrrrr", "writ_at (1i) "= > "2010", "writ_at (2i) "=>" 5 ", "writ_at (3i)" => "4"} Как я могу построить объект для использования begin_of_day?
rtacconi

Это то, что мне нужно: purab.wordpress.com/2009/06/16/…
rtacconi

2
Мне больше нравится этот метод, чем принятый ответ, потому что он не использует date()функцию уровня db ; это потенциально более независимый от БД.
Крейг Уокер,

10

Я запустил этот код, чтобы проверить, сработал ли проверенный ответ, и попытался поменять местами даты, чтобы получить правильный ответ. Это сработало

Day.where(:reference_date => 3.months.ago..Time.now).count
#=> 721

Если вы думаете, что результат должен был быть 36, подумайте, сэр, сколько дней 3 дня для 3 человек?



5

Я использовал 3 точки вместо 2. Три точки дают вам диапазон, который открыт в начале и закрыт в конце, поэтому, если вы сделаете 2 запроса для последующих диапазонов, вы не сможете вернуть ту же строку в обе.

2.2.2 :003 > Comment.where(updated_at: 2.days.ago.beginning_of_day..1.day.ago.beginning_of_day)
Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE ("comments"."updated_at" BETWEEN '2015-07-12 00:00:00.000000' AND '2015-07-13 00:00:00.000000')
=> #<ActiveRecord::Relation []> 
2.2.2 :004 > Comment.where(updated_at: 2.days.ago.beginning_of_day...1.day.ago.beginning_of_day)
Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE ("comments"."updated_at" >= '2015-07-12 00:00:00.000000' AND "comments"."updated_at" < '2015-07-13 00:00:00.000000')
=> #<ActiveRecord::Relation []> 

И, да, всегда приятно использовать прицел!


4

Если вы хотите получить только один день, это будет проще:

Comment.all(:conditions => ["date(created_at) = ?", some_date])

4

Есть несколько способов. Вы можете использовать этот метод:

start = @selected_date.beginning_of_day
end = @selected_date.end_of_day
@comments = Comment.where("DATE(created_at) BETWEEN ? AND ?", start, end)

Или это:

@comments = Comment.where(:created_at => @selected_date.beginning_of_day..@selected_date.end_of_day)

4

На это, я считаю, должно быть поведение активной записи по умолчанию. Запрашивать даты сложно, особенно когда задействованы часовые пояса.

Во всяком случае, я использую:

  scope :between, ->(start_date=nil, end_date=nil) {
    if start_date && end_date
      where("#{self.table_name}.created_at BETWEEN :start AND :end", start: start_date.beginning_of_day, end: end_date.end_of_day)
    elsif start_date
      where("#{self.table_name}.created_at >= ?", start_date.beginning_of_day)
    elsif end_date
      where("#{self.table_name}.created_at <= ?", end_date.end_of_day)
    else
      all
    end
  }

1

Вы можете использовать ниже гем, чтобы найти записи между датами,

Этот драгоценный камень довольно прост в использовании и более понятен. Звездой я использую этот драгоценный камень и API, более понятный и хорошо объясненный документацией.

Post.between_times(Time.zone.now - 3.hours,  # all posts in last 3 hours
                  Time.zone.now)

Здесь вы также можете пройти наше поле Post.by_month("January", field: :updated_at)

Пожалуйста, посмотрите документацию и попробуйте.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.