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'"

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)

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.


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)

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


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?


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

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!


4

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

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

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)

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
  }

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.