Rails ActiveRecord tanggal antara

171

Saya perlu menanyakan komentar yang dibuat dalam satu hari. Bidang adalah bagian dari stempel waktu standar, adalah created_at. Tanggal yang dipilih berasal dari a date_select.

Bagaimana saya bisa menggunakannya ActiveRecorduntuk melakukan itu?

Saya butuh sesuatu seperti:

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

Jawaban:

402

Hanya perhatikan bahwa jawaban yang saat ini diterima tidak berlaku lagi di Rails 3. Anda harus melakukan ini sebagai gantinya:

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

Atau, jika Anda ingin atau harus menggunakan kondisi string murni , Anda dapat melakukan:

Comment.where('created_at BETWEEN ? AND ?', @selected_date.beginning_of_day, @selected_date.end_of_day)
ndbroadbent
sumber
9
Day.where (: reference_date => 6.months.ago..Time.now) berfungsi, terima kasih
boulder_ruby
4
Bukankah ini akan membuat objek rentang besar?
Kasper Grubbe
3
@KasperGrubbe jika Anda menggunakan rentang dengan sendirinya, tetapi Rails hanya menggunakan nilai pertama dan terakhir
Dex
4
@KasperGrubbe @Dex Bukan Rails yang melakukan itu. Kelas Rentang di Ruby hanya menyimpan batas bawah dan atas. Ini berjalan dengan baik di irb: 1..1000000000000Saya tidak jelas tentang apa yang Anda maksud dengan 'menggunakan rentang dengan sendirinya'
Connor Clark
11
+1 Kami juga dapat menjadikannya ruang lingkup: scope :between, -> (a, b) { where(created_at: a..b) }
rebagliatte
48

Saya pribadi akan menciptakan ruang lingkup untuk membuatnya lebih mudah dibaca dan digunakan kembali:

Di Anda Comment.rb, Anda bisa menentukan ruang lingkup:

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

Kemudian untuk kueri yang dibuat antara:

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

Semoga ini bisa membantu.

Marshall Shen
sumber
4
Pendekatan yang sangat bersih ... sempurna !!
Joseph N.
Kembali untuk memilih jawaban ini karena saya mencari masalah ini. Dianggap salah di sintaks, diasumsikan #between?menerima rentang.
Tass
28

Rails 5.1 memperkenalkan metode penolong tanggal yang baru all_day, lihat: 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

Jika Anda menggunakan Rails 5.1, kueri akan terlihat seperti:

Comment.where(created_at: @selected_date.all_day)
Bismark
sumber
1
Mulia. Ini sebenarnya adalah bagian dari permata ActiveSupport (dan selanjutnya seluruh ekosistem ActiveRecord), sehingga berfungsi di luar Rails juga! Adil require 'active_record'dan Anda sudah siap!
Master of Ducks
24

Kode ini bisa digunakan untuk Anda:

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

Untuk info lebih lanjut, lihat perhitungan Waktu

Catatan: Kode ini sudah usang . Gunakan kode dari jawaban jika Anda menggunakan Rails 3.1 / 3.2

Irukandji
sumber
OK tapi dari formulir saya mendapatkan ini: {"writed_at (4i)" => "18", "writed_at (5i)" => "56", "content" => "rrrrrr", "wrote_at (1i)" = > "2010", "ditulis_at (2i)" => "5", "ditulis_at (3i)" => "4"} Bagaimana saya bisa membangun objek untuk menggunakan awal_of_day?
rtacconi
Inilah yang saya butuhkan: purab.wordpress.com/2009/06/16/…
rtacconi
2
Saya suka metode ini daripada jawaban yang diterima karena tidak bergantung pada fungsi db-level date(); itu berpotensi lebih db independen.
Craig Walker
10

Saya menjalankan kode ini untuk melihat apakah jawaban yang diperiksa berhasil, dan harus mencoba bertukar tanggal untuk memperbaikinya. Ini bekerja -

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

Jika Anda berpikir outputnya seharusnya 36, ​​pertimbangkan ini, Pak, berapa hari adalah 3 hari untuk 3 orang?

boulder_ruby
sumber
6
Comment.find(:all, :conditions =>["date(created_at) BETWEEN ? AND ? ", '2011-11-01','2011-11-15'])
sharma kaushal
sumber
5

Saya telah menggunakan 3 titik, bukan 2. Tiga titik memberi Anda rentang yang terbuka di awal dan ditutup di akhir, jadi jika Anda melakukan 2 kueri untuk rentang berikutnya, Anda tidak bisa mendapatkan baris yang sama kembali kedua.

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 []> 

Dan, ya, selalu menyenangkan untuk menggunakan lingkup!

nroose
sumber
4

Jika Anda hanya ingin mendapatkan satu hari akan lebih mudah dengan cara ini:

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

ada beberapa cara. Anda dapat menggunakan metode ini:

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

Atau ini:

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

Seharusnya ada perilaku rekaman aktif default pada saya ini. Tanggal pertanyaan sulit, terutama ketika zona waktu terlibat.

Lagi pula, saya menggunakan:

  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
  }
Augustin Riedinger
sumber
1

Anda dapat menggunakan permata di bawah ini untuk menemukan catatan di antara tanggal,

Permata ini cukup mudah digunakan dan lebih jelas. Dengan bintang saya menggunakan permata ini dan API lebih jelas dan dokumentasi juga dijelaskan dengan baik.

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

Di sini Anda bisa melewati bidang kami juga Post.by_month("January", field: :updated_at)

Silakan lihat dokumentasi dan coba.

Jenorish
sumber