Дати 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 зберігає лише нижню і верхню межі. Це добре працює в Ірбі: 1..1000000000000мені незрозуміло, що ти маєш на увазі під «використанням діапазону сам по собі»
Коннор Кларк,

11
+1 Ми також можемо зробити це сферою застосування: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte

48

Я особисто створив би сферу, щоб зробити її легшою для читання та повторного використання:

У вашому коментарі.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 представив новий допоміжний метод дати 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


Гаразд, але з форми я отримую це: {"wrote_at (4i)" => "18", "write_at (5i)" => "56", "content" => "rrrrrr", "write_at (1i)" = > "2010", "write_at (2i)" => "5", "write_at (3i)" => "4"} Як я можу створити об'єкт для використання begin_of_day?
rtacconi

Це те, що мені потрібно: purab.wordpress.com/2009/06/16/…
rtacconi

2
Мені подобається цей метод над прийнятою відповіддю, оскільки він не покладається на date()функцію рівня db ; це потенційно більше 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.